@@ -18,6 +18,7 @@ use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
1818// A "full" atom is a traditional length + identifier, followed by a version (1) and flags (3)
1919const FULL_ATOM_SIZE : u64 = ATOM_HEADER_LEN + 4 ;
2020const HDLR_SIZE : u64 = ATOM_HEADER_LEN + 25 ;
21+ const DEFAULT_PADDING_SIZE : u32 = 1024 ;
2122
2223// TODO: We are forcing the use of ParseOptions::DEFAULT_PARSING_MODE. This is not good. It should be caller-specified.
2324pub ( crate ) fn write_to < ' a , I : ' a > ( data : & mut File , tag : & mut IlstRef < ' a , I > ) -> Result < ( ) >
@@ -282,10 +283,7 @@ fn save_to_existing(
282283 write_handle. write_all ( & ilst) ?;
283284
284285 // Write the remaining padding
285- write_handle. write_u32 :: < BigEndian > ( remaining_space) ?;
286- write_handle. write_all ( b"free" ) ?;
287- write_handle
288- . write_all ( & try_vec ! [ 1 ; ( remaining_space - ATOM_HEADER_LEN as u32 ) as usize ] ) ?;
286+ write_free_atom ( & mut write_handle, remaining_space) ?;
289287
290288 return Ok ( ( ) ) ;
291289 }
@@ -311,10 +309,38 @@ fn save_to_existing(
311309 write_handle. write_atom_size ( udta. start , * new_udta_size, udta. extended ) ?;
312310
313311 // Update offset atoms
314- drop ( write_handle) ;
315312
316- let difference = ( new_meta_size as i64 ) - ( meta. len as i64 ) ;
317- update_offsets ( writer, moov, difference) ?;
313+ let mut difference = ( new_meta_size as i64 ) - ( meta. len as i64 ) ;
314+ if difference. is_negative ( ) {
315+ let diff_abs = difference. abs ( ) ;
316+ if diff_abs >= 8 {
317+ log:: trace!(
318+ "Avoiding offset update, padding tag with {} bytes" ,
319+ diff_abs
320+ ) ;
321+
322+ // If our difference is >= 8, we can make up the difference with
323+ // a `free` atom and skip updating the offsets.
324+ write_free_atom ( & mut write_handle, diff_abs as u32 ) ?;
325+ difference = 0 ;
326+ } else {
327+ log:: trace!(
328+ "Cannot avoid offset update, padding tag with {} bytes" ,
329+ DEFAULT_PADDING_SIZE
330+ ) ;
331+
332+ // Otherwise, we'll have to just pad the default amount,
333+ // and update the offsets.
334+ write_free_atom ( & mut write_handle, DEFAULT_PADDING_SIZE ) ?;
335+ difference += i64:: from ( DEFAULT_PADDING_SIZE ) ;
336+ }
337+ }
338+
339+ drop ( write_handle) ;
340+ if difference != 0 {
341+ let offset = range. start as u64 ;
342+ update_offsets ( writer, moov, difference, offset) ?;
343+ }
318344 }
319345
320346 // Replace the `ilst` atom
@@ -325,7 +351,22 @@ fn save_to_existing(
325351 Ok ( ( ) )
326352}
327353
328- fn update_offsets ( writer : & AtomWriter , moov : & ContextualAtom , difference : i64 ) -> Result < ( ) > {
354+ fn write_free_atom < W > ( writer : & mut W , size : u32 ) -> Result < ( ) >
355+ where
356+ W : Write ,
357+ {
358+ writer. write_u32 :: < BigEndian > ( size) ?;
359+ writer. write_all ( b"free" ) ?;
360+ writer. write_all ( & try_vec ! [ 1 ; ( size - ATOM_HEADER_LEN as u32 ) as usize ] ) ?;
361+ Ok ( ( ) )
362+ }
363+
364+ fn update_offsets (
365+ writer : & AtomWriter ,
366+ moov : & ContextualAtom ,
367+ difference : i64 ,
368+ offset : u64 ,
369+ ) -> Result < ( ) > {
329370 log:: debug!( "Checking for offset atoms to update" ) ;
330371
331372 let mut write_handle = writer. start_write ( ) ;
@@ -343,14 +384,17 @@ fn update_offsets(writer: &AtomWriter, moov: &ContextualAtom, difference: i64) -
343384
344385 let count = write_handle. read_u32 :: < BigEndian > ( ) ?;
345386 for _ in 0 ..count {
346- let offset = write_handle. read_u32 :: < BigEndian > ( ) ?;
387+ let read_offset = write_handle. read_u32 :: < BigEndian > ( ) ?;
388+ if u64:: from ( read_offset) < offset {
389+ continue ;
390+ }
347391 write_handle. seek ( SeekFrom :: Current ( -4 ) ) ?;
348- write_handle. write_u32 :: < BigEndian > ( ( i64:: from ( offset ) + difference) as u32 ) ?;
392+ write_handle. write_u32 :: < BigEndian > ( ( i64:: from ( read_offset ) + difference) as u32 ) ?;
349393
350394 log:: trace!(
351395 "Updated offset from {} to {}" ,
352396 offset,
353- ( i64 :: from( offset ) + difference) as u32
397+ ( i64 :: from( read_offset ) + difference) as u32
354398 ) ;
355399 }
356400 }
@@ -368,14 +412,18 @@ fn update_offsets(writer: &AtomWriter, moov: &ContextualAtom, difference: i64) -
368412
369413 let count = write_handle. read_u32 :: < BigEndian > ( ) ?;
370414 for _ in 0 ..count {
371- let offset = write_handle. read_u64 :: < BigEndian > ( ) ?;
415+ let read_offset = write_handle. read_u64 :: < BigEndian > ( ) ?;
416+ if read_offset < offset {
417+ continue ;
418+ }
419+
372420 write_handle. seek ( SeekFrom :: Current ( -8 ) ) ?;
373- write_handle. write_u64 :: < BigEndian > ( ( offset as i64 + difference) as u64 ) ?;
421+ write_handle. write_u64 :: < BigEndian > ( ( read_offset as i64 + difference) as u64 ) ?;
374422
375423 log:: trace!(
376424 "Updated offset from {} to {}" ,
377425 offset,
378- ( ( offset as i64 ) + difference) as u64
426+ ( ( read_offset as i64 ) + difference) as u64
379427 ) ;
380428 }
381429 }
@@ -402,9 +450,13 @@ fn update_offsets(writer: &AtomWriter, moov: &ContextualAtom, difference: i64) -
402450 let base_data_offset = ( flags & 0b1 ) != 0 ;
403451
404452 if base_data_offset {
405- let offset = write_handle. read_u64 :: < BigEndian > ( ) ?;
453+ let read_offset = write_handle. read_u64 :: < BigEndian > ( ) ?;
454+ if read_offset < offset {
455+ continue ;
456+ }
457+
406458 write_handle. seek ( SeekFrom :: Current ( -8 ) ) ?;
407- write_handle. write_u64 :: < BigEndian > ( ( offset as i64 + difference) as u64 ) ?;
459+ write_handle. write_u64 :: < BigEndian > ( ( read_offset as i64 + difference) as u64 ) ?;
408460
409461 log:: trace!(
410462 "Updated offset from {} to {}" ,
0 commit comments