1use crate::base::*;
2use std::fmt::Debug;
3
4pub(crate) trait Mp4BoxTrait: Debug {
6 const TYPE: u32; fn parse_full(input: &[u8], state: &mut ParserState) -> Self;
9 fn parse(input: &[u8], state: &mut ParserState, header: &Option<(u8, u32)>) -> Self;
10
11 fn write_full(&self, output: &mut Vec<u8>);
12 fn write(&self, output: &mut Vec<u8>);
13}
14
15pub(crate) fn read_header<'a>(input: &'a [u8], state: &mut ParserState) -> (u32, &'a [u8]) {
16 let size = read(input, state, 4).unwrap();
17 let size = u32::from_be_bytes([size[0], size[1], size[2], size[3]]);
18
19 let type_ = read(input, state, 4).unwrap();
20 let type_ = u32::from_ne_bytes([type_[0], type_[1], type_[2], type_[3]]);
21
22 (type_, read(input, state, size as usize - 8).unwrap())
23}
24
25pub(crate) fn read_fullbox_header(input: &[u8], state: &mut ParserState) -> (u8, u32) {
26 let version = read(input, state, 1).unwrap()[0];
27 let flags = read(input, state, 3).unwrap();
28 let flags = u32::from_be_bytes([0, flags[0], flags[1], flags[2]]);
29
30 (version, flags)
31}
32
33macro_rules! mp4box_gen {
34 { @read $input:ident $state:ident $header:ident; u8 } => {
36 read($input, $state, 1).unwrap()[0]
37 };
38 { @read $input:ident $state:ident $header:ident; u16 } => {
39 {
40 let slice = read($input, $state, 2).unwrap();
41 u16::from_be_bytes([slice[0], slice[1]])
42 }
43 };
44 { @read $input:ident $state:ident $header:ident; u32 } => {
45 {
46 let slice = read($input, $state, 4).unwrap();
47 u32::from_be_bytes([slice[0], slice[1], slice[2], slice[3]])
48 }
49 };
50 { @read $input:ident $state:ident $header:ident; u64 } => {
51 {
52 let slice = read($input, $state, 8).unwrap();
53 u64::from_be_bytes([slice[0], slice[1], slice[2], slice[3], slice[4], slice[5], slice[6], slice[7]])
54 }
55 };
56 { @read $input:ident $state:ident $header:ident; i8 } => {
57 read($input, $state, 1).unwrap()[0] as i8
58 };
59 { @read $input:ident $state:ident $header:ident; i16 } => {
60 {
61 let slice = read($input,$state, 2).unwrap();
62 i16::from_be_bytes([slice[0], slice[1]])
63 }
64 };
65 { @read $input:ident $state:ident $header:ident; i32 } => {
66 {
67 let slice = read($input, $state, 4).unwrap();
68 i32::from_be_bytes([slice[0], slice[1], slice[2], slice[3]])
69 }
70 };
71 { @read $input:ident $state:ident $header:ident; i64 } => {
72 {
73 let slice = read($input, $state, 8).unwrap();
74 i64::from_be_bytes([slice[0], slice[1], slice[2], slice[3], slice[4], slice[5], slice[6], slice[7]])
75 }
76 };
77 { @read $input:ident $state:ident $header:ident; f32 } => {
78 {
79 let slice = read($input, $state, 4).unwrap();
80 f32::from_be_bytes([slice[0], slice[1], slice[2], slice[3]])
81 }
82 };
83 { @read $input:ident $state:ident $header:ident; f64 } => {
84 {
85 let slice = read($input, $state, 8).unwrap();
86 f64::from_be_bytes([slice[0], slice[1], slice[2], slice[3], slice[4], slice[5], slice[6], slice[7]])
87 }
88 };
89 { @read $input:ident $state:ident $header:ident; [$type:tt; $n:expr] } => { {
91 let mut array = [0; $n];
92 for i in 0..$n {
93 array[i] = mp4box_gen! { @read $input $state $header; $type };
94 }
95 array
96 }
97 };
98 { @read $input:ident $state:ident $header:ident; Mp4Box } => {
99 parse_box($input, $state).unwrap()
100 };
101 { @read $input:ident $state:ident $header:ident; String } => {
102 {
103 let mut string = String::new();
105
106 let mut bytes = Vec::new();
107 while let Some(byte) = read($input, $state, 1) {
108 if byte[0] == 0 {
109 break;
110 }
111
112 match byte[0] {
114 0..=0x7F => {
115 bytes.push(byte[0]);
117 },
118 0xC0..=0xDF => {
119 bytes.push(byte[0]);
121 bytes.push(read($input, $state, 1).unwrap()[0]);
122 },
123 0xE0..=0xEF => {
124 bytes.push(byte[0]);
126 bytes.push(read($input, $state, 1).unwrap()[0]);
127 bytes.push(read($input, $state, 1).unwrap()[0]);
128 },
129 0xF0..=0xF7 => {
130 bytes.push(byte[0]);
132 bytes.push(read($input, $state, 1).unwrap()[0]);
133 bytes.push(read($input, $state, 1).unwrap()[0]);
134 bytes.push(read($input, $state, 1).unwrap()[0]);
135 },
136 _ => panic!("Invalid utf8 character"),
137 }
138 }
139
140 string.push_str(std::str::from_utf8(&bytes).unwrap());
142
143 string
144 }
145 };
146
147
148 { @read $input:ident $state:ident $header:ident; $($type:tt)* } => {
150 <$($type)*>::parse($input, $state, &$header)
152 };
153
154 { @write $output:ident $($item:ident).+; &u8 } => {
156 $output.push(*$($item).+);
157 };
158 { @write $output:ident $($item:ident).+; u8 } => {
159 $output.push($($item).+);
160 };
161 { @write $output:ident $($item:ident).+; &u16 } => {
162 $output.extend_from_slice(&u16::to_be_bytes(*$($item).+))
163 };
164 { @write $output:ident $($item:ident).+; u16 } => {
165 $output.extend_from_slice(&u16::to_be_bytes($($item).+))
166 };
167 { @write $output:ident $($item:ident).+; &u32 } => {
168 $output.extend_from_slice(&u32::to_be_bytes(*$($item).+))
169 };
170 { @write $output:ident $($item:ident).+; u32 } => {
171 $output.extend_from_slice(&u32::to_be_bytes($($item).+))
172 };
173 { @write $output:ident $($item:ident).+; &u64 } => {
174 $output.extend_from_slice(&u64::to_be_bytes(*$($item).+))
175 };
176 { @write $output:ident $($item:ident).+; u64 } => {
177 $output.extend_from_slice(&u64::to_be_bytes($($item).+))
178 };
179 { @write $output:ident $($item:ident).+; i8 } => {
180 $output.push($($item).+ as u8)
181 };
182 { @write $output:ident $($item:ident).+; i16 } => {
183 $output.extend_from_slice(&i16::to_be_bytes($($item).+))
184 };
185 { @write $output:ident $($item:ident).+; &i32 } => {
186 $output.extend_from_slice(&i32::to_be_bytes(*$($item).+))
187 };
188 { @write $output:ident $($item:ident).+; i32 } => {
189 $output.extend_from_slice(&i32::to_be_bytes($($item).+))
190 };
191 { @write $output:ident $($item:ident).+; i64 } => {
192 $output.extend_from_slice(&i64::to_be_bytes($($item).+))
193 };
194 { @write $output:ident $($item:ident).+; f32 } => {
195 $output.extend_from_slice(&f32::to_be_bytes($($item).+))
196 };
197 { @write $output:ident $($item:ident).+; f64 } => {
198 $output.extend_from_slice(&f64::to_be_bytes($($item).+))
199 };
200 { @write $output:ident $($item:ident).+; [$type:tt; $n:expr] } => { for entry in $($item).+ {
202 mp4box_gen! { @write $output entry; $type };
203 }
204 };
205 { @write $output:ident $($item:ident).+; &[$type:tt; $n:expr] } => { for entry in $($item).+ {
207 let entry = *entry;
208 mp4box_gen! { @write $output entry; $type };
209 }
210 };
211 { @write $output:ident $($item:ident).+; String } => {
212 $output.extend_from_slice($($item).+.as_bytes());
213 };
214
215 { @write $output:ident $($item:ident).+; $($type:tt)* } => {
217 $($item).+.write($output);
218 };
219
220 { @cond read
224 $input:ident $state:ident $header:ident;
225 [Vec<$type:tt, Remain>],
226 } => {
227 {
228 let length = ($input.len() - $state.offset) / std::mem::size_of::<$type>();
229 let mut vec = Vec::with_capacity(length);
230 for _ in 0..length {
231 vec.push(mp4box_gen! { @read $input $state $header; $type });
232 }
233 vec
234 }
235 };
236 { @cond read
238 $input:ident $state:ident $header:ident;
239 [Vec<$type:tt, $length:ident>],
240 } => {
241 {
242 let length = $length as usize;
243 let mut vec = Vec::with_capacity(length);
244 for _ in 0..length {
245 vec.push(mp4box_gen! { @read $input $state $header; $type });
246 }
247 vec
248 }
249 };
250 { @cond read
252 $input:ident $state:ident $header:ident;
253 [Vec<$type:tt, Option<[$($length:tt)*]>>],
254 } => {
255 {
256 let length = ($($length)*) as usize;
257 let mut vec = Vec::with_capacity(length);
258 for _ in 0..length {
259 vec.push(mp4box_gen! { @read $input $state $header; $type });
260 }
261 vec
262 }
263 };
264 { @cond read $($opt:ident)*;
266 [$type:tt],
267 } => {
268 mp4box_gen! { @read $($opt)*; $type }
269 };
270
271 { @cond read $($opt:ident)*;
274 [Either<$type:tt, [$($btype:tt)*]>],
275 $cond:expr,
276 $($rest:tt)*
277 } => {
278 if $cond {
279 Either::A(mp4box_gen! { @cond read $($opt)*; [$type], })
280 } else {
281 Either::B(mp4box_gen! { @cond read $($opt)*; [$($btype)*], $($rest)* })
282 }
283 };
284 { @cond read $($opt:ident)*;
286 [Option<[$($type:tt)*]>],
287 $cond:expr,
288 $($rest:tt)*
289 } => {
290 if $cond {
291 Some(mp4box_gen! { @cond read $($opt)*; [$($type)*], $($rest)* })
292 } else {
293 None
294 }
295 };
296
297 { @cond write
300 $output:ident $($item:ident).+;
301 [&Vec<$type:tt, $length:ident>],
302 } => {
303 for entry in $($item).+ {
304 mp4box_gen! { @write $output entry; $type };
305 }
306 };
307 { @cond write
309 $output:ident $($item:ident).+;
310 [&Vec<$type:tt, Option<[$($length:tt)*]>>],
311 } => {
312 for entry in $($item).+ {
313 mp4box_gen! { @write $output entry; $type };
314 }
315 };
316 { @cond write
318 $output:ident $($item:ident).+;
319 [Vec<$type:tt, $length:ident>],
320 } => {
321 for entry in &$($item).+ {
322 mp4box_gen! { @write $output entry; &$type };
323 }
324 };
325 { @cond write
327 $output:ident $($item:ident).+;
328 [Vec<$type:tt, Option<[$($length:tt)*]>>],
329 } => {
330 for entry in $($item).+ {
331 mp4box_gen! { @write $output entry; $type };
332 }
333 };
334 { @cond write
336 $output:ident $($item:ident).+;
337 [$type:tt],
338 } => {
339 mp4box_gen! { @write $output $($item).+; $type }
340 };
341 { @cond write
343 $output:ident $($item:ident).+;
344 [&$type:tt],
345 } => {
346 mp4box_gen! { @write $output $($item).+; &$type }
347 };
348
349 { @cond write
352 $output:ident $($item:ident).+;
353 [&Either<$type:tt, [$($btype:tt)*]>],
354 $cond:expr,
355 $($rest:tt)*
356 } => {
357 match $($item).+ {
358 Either::A(item) => mp4box_gen! { @cond write $output item; [&$type], },
359 Either::B(item) => mp4box_gen! { @cond write $output item; [&$($btype)*], $($rest)* },
360 }
361 };
362 { @cond write
364 $output:ident $($item:ident).+;
365 [Either<$type:tt, [$($btype:tt)*]>],
366 $cond:expr,
367 $($rest:tt)*
368 } => {
369 match $($item).+ {
370 Either::A(item) => mp4box_gen! { @cond write $output item; [$type], },
371 Either::B(item) => mp4box_gen! { @cond write $output item; [$($btype)*], $($rest)* },
372 }
373 };
374 { @cond write
376 $output:ident $($item:ident).+;
377 [&Option<[$($type:tt)*]>],
378 $cond:expr,
379 $($rest:tt)*
380 } => {
381 if let Some(item) = $($item).+ {
382 mp4box_gen! { @cond write $output item; [&$($type)*], $($rest)* }
383 }
384 };
385 { @cond write
387 $output:ident $($item:ident).+;
388 [Option<[$($type:tt)*]>],
389 $cond:expr,
390 $($rest:tt)*
391 } => {
392 if let Some(item) = &$($item).+ {
393 mp4box_gen! { @cond write $output item; [&$($type)*], $($rest)* }
394 }
395 };
396
397 {
400 @expand $version:ident $flags:ident;
401 $name:ident Full {}; [
403 $([
404 $field:ident, [$($ftype:tt)*]&[$($ctype:tt)*]; $($cond:expr,)*
405 ],)+ ]
407 } => {
408 use $crate::base::*;
409 use $crate::r#macro::*;
410
411 paste::paste! {
412 #[derive(Debug)]
413 pub struct [<Box $name>] {
414 pub header: Option<(u8, u32)>,
415 $(
416 pub $field: $($ftype)*,
417 )+
418 }
419 impl [<Box $name>] {
420 const IDSTR: &[u8] = bstringify::bstringify!([<$name:lower>]);
421 }
422 impl Mp4BoxTrait for [<Box $name>] {
423 const TYPE: u32 = u32::from_ne_bytes([Self::IDSTR[0], Self::IDSTR[1], Self::IDSTR[2], Self::IDSTR[3]]);
424
425 fn parse_full(input: &[u8], state: &mut ParserState) -> Self {
426 let (version, flags) = read_fullbox_header(input, state);
427 let header = Some((version, flags));
428
429 let mut instance = Self::parse(input, state, &header);
430 instance.header = header;
431 instance
432 }
433
434 fn parse(input: &[u8], state: &mut ParserState, header: &Option<(u8, u32)>) -> Self {
435 let uwh = header.unwrap();
436 let ($version, $flags) = uwh;
437
438 $(
440 let $field = mp4box_gen! {
441 @cond read input state header;
442 [$($ctype)*],
443 $($cond,)*
444 };
445 )+
446
447 Self {
448 header: None,
449 $(
450 $field,
451 )+
452 }
453 }
454
455 fn write_full(&self, output: &mut Vec<u8>) {
456 let mut data = Vec::new();
457 self.write(&mut data);
458
459 let size = data.len() as u32 + 12;
461 output.extend_from_slice(&u32::to_be_bytes(size)); output.extend_from_slice(&u32::to_ne_bytes(Self::TYPE)); let (version, flags) = self.header.unwrap();
466 output.push(version); output.extend_from_slice(&u32::to_be_bytes(flags)[1..]); output.extend(data);
470 }
471
472 fn write(&self, output: &mut Vec<u8>) {
473 $(
474 mp4box_gen! {
475 @cond write output self.$field;
476 [$($ctype)*],
477 $($cond,)*
478 };
479 )+
480 }
481 }
482 }
483 };
484
485 {
487 @expand $version:ident $flags:ident;
488 $name:ident {}; [
490 $([
491 $field:ident, [$($ftype:tt)*]&[$($ctype:tt)*]; $($cond:expr,)*
492 ],)+ ]
494 } => {
495 use $crate::base::*;
496 use $crate::r#macro::*;
497
498 paste::paste! {
499 #[derive(Debug)]
500 pub struct [<Box $name>] {
501 $(
502 pub $field: $($ftype)*,
503 )+
504 }
505 impl [<Box $name>] {
506 const IDSTR: &[u8] = bstringify::bstringify!([<$name:lower>]);
507 }
508 impl Mp4BoxTrait for [<Box $name>] {
509 const TYPE: u32 = u32::from_ne_bytes([Self::IDSTR[0], Self::IDSTR[1], Self::IDSTR[2], Self::IDSTR[3]]);
510
511 fn parse_full(input: &[u8], state: &mut ParserState) -> Self {
512 Self::parse(input, state, &None)
513 }
514
515 fn parse(input: &[u8], state: &mut ParserState, _: &Option<(u8, u32)>) -> Self {
516 $(
518 let $field = mp4box_gen! {
519 @cond read input state header;
520 [$($ctype)*],
521 $($cond,)*
522 };
523 )+
524
525 Self {
526 $(
527 $field,
528 )+
529 }
530 }
531
532 fn write_full(&self, output: &mut Vec<u8>) {
533 let mut data = Vec::new();
534 self.write(&mut data);
535
536 let size = data.len() as u32 + 8;
538 output.extend_from_slice(&u32::to_be_bytes(size)); output.extend_from_slice(&u32::to_ne_bytes(Self::TYPE)); output.extend(data);
541 }
542
543 fn write(&self, output: &mut Vec<u8>) {
544 $(
545 mp4box_gen! {
546 @cond write output self.$field;
547 [$($ctype)*],
548 $($cond,)*
549 };
550 )+
551 }
552 }
553 }
554 };
555
556 { @cond_expand $version:ident $flags:ident;
559 $name:ident $($stype:ident)? {
560 [],
561 $($rest:tt)* }; [$($prev:tt)*], [$field:ident, [$($ftype:tt)*]&[$($ctype:tt)*]; $($done:tt)*] } => {
565 mp4box_gen! {
566 @expand $version $flags;
567 $name $($stype)? {
568 $($rest)* }; [
570 $($prev)* [$field, [$($ftype)*]&[$($ctype)*]; $($done)*],
572 ]
573 }
574 };
575 { @cond_expand $version:ident $flags:ident;
577 $name:ident $($stype:ident)? {
578 [] [if $cond:expr],
579 $($rest:tt)* }; [$($prev:tt)*], [$field:ident, [$($ftype:tt)*]&[$($ctype:tt)*]; $($done:tt)*] } => {
583 mp4box_gen! {
584 @expand $version $flags;
585 $name $($stype)? {
586 $($rest)* }; [
588 $($prev)* [$field, [Option<$($ftype)*>]&[Option<[$($ctype)*]>]; $cond, $($done)*],
590 ]
591 }
592 };
593 { @cond_expand $version:ident $flags:ident;
595 $name:ident $($stype:ident)? {
596 [$type:tt, $($rtype:tt,)*] [if $cond:expr] $([if $rcond:expr])*,
597 $($rest:tt)* }; [$($prev:tt)*], [$field:ident, [$($ftype:tt)*]&[$($ctype:tt)*]; $($done:tt)*] } => {
601 mp4box_gen! {
602 @cond_expand $version $flags;
603 $name $($stype)? {
604 [$($rtype,)*] $([if $rcond])*,
605 $($rest)* }; [$($prev)*], [$field, [Either<$type,$($ftype)*>]&[Either<$type,[$($ctype)*]>]; $cond, $($done)*]
608 }
609 };
610
611 { @expand $version:ident $flags:ident;
615 $name:ident $($stype:ident)? {
616 $field:ident: [$($type:tt)*] {
617 $(
618 $ifield:ident: $iftype:tt $({$($ifsdef:tt)+})? $([if $ifcond:expr])*
619 ),+ $(,)?
620 } [if $cond:expr],
621 $($rest:tt)* }; [$($prev:tt)*] } => {
624 paste::paste! {
625 mp4box_gen! {
626 @expand $version $flags;
627 [<$name:camel $field:camel Type>] $($stype)? {
628 $(
629 $ifield: $iftype $({$($ifsdef)+})? $([if $ifcond])*,
630 )+
631 }; []
632 }
633 mp4box_gen! {
634 @expand $version $flags;
635 $name $($stype)? {
636 $($rest)* }; [
638 $($prev)* [$field, [Option<Vec<[<Box $name:camel $field:camel Type>]>>]&[Option<[Vec<[<Box $name:camel $field:camel Type>], Option<[$($type)*]>>]>]; $cond,],
640 ]
641 }
642 }
643 };
644 { @expand $version:ident $flags:ident;
646 $name:ident $($stype:ident)? {
647 $field:ident: [$type:ident] {
648 $(
649 $ifield:ident: $iftype:tt $({$($ifsdef:tt)+})? $([if $ifcond:expr])*
650 ),+ $(,)?
651 },
652 $($rest:tt)* }; [$($prev:tt)*] } => {
655 paste::paste! {
656 mp4box_gen! {
657 @expand $version $flags;
658 [<$name:camel $field:camel Type>] $($stype)? {
659 $(
660 $ifield: $iftype $({$($ifsdef)+})? $([if $ifcond])*,
661 )+
662 }; []
663 }
664 mp4box_gen! {
665 @expand $version $flags;
666 $name $($stype)? {
667 $($rest)* }; [
669 $($prev)* [$field, [Vec<[<Box $name:camel $field:camel Type>]>]&[Vec<[<Box $name:camel $field:camel Type>], $type>]; ],
671 ]
672 }
673 }
674 };
675
676 { @expand $version:ident $flags:ident;
679 $name:ident $($stype:ident)? {
680 $field:ident: [$ftype:tt, $($type:tt),+ $(,)?] $([if $cond:expr])+,
681 $($rest:tt)* }; [$($prev:tt)*] } => {
684 mp4box_gen! {
685 @cond_expand $version $flags;
686 $name $($stype)? {
687 [$($type,)*] $([if $cond])+,
688 $($rest)* }; [
690 $($prev)* ], [$field, [$ftype]&[$ftype]; ]
692 }
693 };
694 { @expand $version:ident $flags:ident;
696 $name:ident $($stype:ident)? {
697 $field:ident: $type:tt [if $cond:expr],
698 $($rest:tt)* }; [$($prev:tt)*] } => {
701 mp4box_gen! {
702 @expand $version $flags;
703 $name $($stype)? {
704 $($rest)* }; [
706 $($prev)* [$field, [Option<$type>]&[Option<[$type]>]; $cond,],
708 ]
709 }
710 };
711 { @expand $version:ident $flags:ident;
713 $name:ident $($stype:ident)? {
714 $field:ident: Vec<$type:tt>,
715 $($rest:tt)* }; [$($prev:tt)*] } => {
718 mp4box_gen! {
719 @expand $version $flags;
720 $name $($stype)? {
721 $($rest)* }; [
723 $($prev)* [$field, [Vec<$type>]&[Vec<$type, Remain>];],
725 ]
726 }
727 };
728 { @expand $version:ident $flags:ident;
730 $name:ident $($stype:ident)? {
731 $field:ident: $type:tt,
732 $($rest:tt)* }; [$($prev:tt)*] } => {
735 mp4box_gen! {
736 @expand $version $flags;
737 $name $($stype)? {
738 $($rest)* }; [
740 $($prev)* [$field, [$type]&[$type];],
742 ]
743 }
744 };
745
746 {
748 @expand $version:ident $flags:ident;
749 $name:ident Container $type:tt
750 } => {
751 use $crate::base::*;
752 use $crate::r#macro::*;
753
754 paste::paste! {
755 pub struct [<Box $name>] {
756 pub data: Vec<$type>,
757 }
758 impl std::fmt::Debug for [<Box $name>] {
759 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
760 if !f.alternate() {
761 write!(f, "{}: {:?}", stringify!($name), self.data)
762 } else {
763 write!(f, "{}: [", stringify!($name))?;
764 for item in &self.data {
765 write!(f, "{:#?}, ", item)?;
766 }
767 write!(f, "]")
768 }
769 }
770 }
771 impl Mp4BoxTrait for [<Box $name>] {
772 const TYPE: u32 = u32::from_ne_bytes(*bstringify::bstringify!([<$name:lower>]));
773
774 fn parse_full(input: &[u8], state: &mut ParserState) -> Self {
775 Self::parse(input, state, &None)
776 }
777
778 fn parse(input: &[u8], state: &mut ParserState, _header: &Option<(u8, u32)>) -> Self {
779 let mut data = vec![];
780 while !is_empty(input, &state) {
781 data.push(mp4box_gen!{ @read input state _header; $type });
782 }
783
784 Self { data }
785 }
786
787 fn write_full(&self, output: &mut Vec<u8>) {
788 let mut data = Vec::new();
789 self.write(&mut data);
790
791 let size = data.len() as u32 + 8;
793 output.extend_from_slice(&u32::to_be_bytes(size));
794 output.extend_from_slice(&u32::to_ne_bytes(Self::TYPE));
795 output.extend(data);
796 }
797
798 fn write(&self, output: &mut Vec<u8>) {
799 for item in &self.data {
800 mp4box_gen! { @write output item; &$type }
801 }
802 }
803 }
804 }
805 };
806 {
807 @expand $version:ident $flags:ident;
808 $name:ident Container
809 } => {
810 mp4box_gen!{@expand $version $flags; $name Container Mp4Box}
811 };
812
813 {
815 @expand $version:ident $flags:ident;
816 $name:ident Skip
817 } => {
818 use $crate::base::*;
819 use $crate::r#macro::*;
820
821 paste::paste! {
822 pub struct [<Box $name>] {
823 pub data: Vec<u8>,
824 }
825 impl std::fmt::Debug for [<Box $name>] {
826 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
827 write!(f, "{}: {:?}", stringify!($name), self.data)
828 }
829 }
830 impl Mp4BoxTrait for [<Box $name>] {
831 const TYPE: u32 = u32::from_ne_bytes(*bstringify::bstringify!([<$name:lower>]));
832
833 fn parse_full(input: &[u8], state: &mut ParserState) -> Self {
834 Self::parse(input, state, &None)
835 }
836
837 fn parse(input: &[u8], state: &mut ParserState, _: &Option<(u8, u32)>) -> Self {
838 let data = read(input, state, input.len() - state.offset).unwrap().to_vec();
840
841 Self { data }
842 }
843
844 fn write_full(&self, output: &mut Vec<u8>) {
845 let mut data = Vec::new();
846 self.write(&mut data);
847
848 let size = data.len() as u32 + 8;
850 output.extend_from_slice(&u32::to_be_bytes(size));
851 output.extend_from_slice(&u32::to_ne_bytes(Self::TYPE));
852 output.extend(data);
853 }
854
855 fn write(&self, output: &mut Vec<u8>) {
856 output.extend(&self.data);
857 }
858 }
859 }
860 };
861
862 {
863 $version:ident $flags:ident;
864 $($sname:ident $(: $stype:ident $(= $svtype:tt)?)? $({
865 $(
866 $field:ident: $ftype:tt$(<$iftype:tt>)? $({$($fsdef:tt)+})? $([if $fcond:expr])*
867 ),+ $(,)?
868 })?),* $(,)? } => {
870 $(mp4box_gen! {
871 @expand $version $flags;
872 $sname $($stype $($svtype)?)? $({
873 $(
874 $field: $ftype$(<$iftype>)? $({$($fsdef)+})? $([if $fcond])*,
875 )+
876 }; [])?
877 })*
878
879 paste::paste! {
880 pub enum Mp4Box {
881 $( $sname(Box<[<Box $sname>]>), )*
882 }
883 impl std::fmt::Debug for Mp4Box {
884 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
885 match self {
886 $( Mp4Box::$sname(box_) => write!(f, "{:?}", box_), )*
887 }
888 }
889 }
890
891 impl Mp4Box {
892 pub(crate) fn write(&self, output: &mut Vec<u8>) {
893 match self {
894 $( Mp4Box::$sname(box_) => box_.write_full(output), )*
895 }
896 }
897 }
898
899 pub(crate) fn parse_box(input: &[u8], state: &mut ParserState) -> Option<Mp4Box> {
900 assert!(!is_empty(input, state));
901 let data = read_header(input, state);
902
903 match data.0 {
904 $([<Box $sname>]::TYPE => {
905 Some(Mp4Box::$sname(Box::new([<Box $sname>]::parse_full(data.1, &mut ParserState { offset: 0 }))))
906 })*
907 _ => panic!("Unknown box type: {}", String::from_utf8_lossy(&u32::to_ne_bytes(data.0))),
908 }
909 }
910 pub(crate) fn is_box_type(box_: &Mp4Box, type_: u32) -> bool {
911 match box_ {
912 $(Mp4Box::$sname(_) => [<Box $sname>]::TYPE == type_),*
913 }
914 }
915 pub(crate) fn get_box_type(box_: &Mp4Box) -> String {
916 let int = match box_ {
917 $(Mp4Box::$sname(_) => [<Box $sname>]::TYPE),*
918 };
919 String::from_utf8(u32::to_ne_bytes(int).to_vec()).unwrap()
920 }
921 }
922 };
923}
924
925pub(crate) use mp4box_gen;