Example #1
0
        /// <summary>
        ///    Saves the changes made in the current instance to the
        ///    file it represents.
        /// </summary>
        public override void Save()
        {
            if (udta_boxes.Count == 0)
            {
                IsoUserDataBox udtaBox = new IsoUserDataBox();
                udta_boxes.Add(udtaBox);
            }

            // Try to get into write mode.
            Mode = File.AccessMode.Write;
            try
            {
                FileParser parser = new FileParser(this);
                parser.ParseBoxHeaders();

                InvariantStartPosition = parser.MdatStartPosition;
                InvariantEndPosition   = parser.MdatEndPosition;

                long size_change    = 0;
                long write_position = 0;

                // To avoid rewriting udta blocks which might not have been modified,
                // the code here will work correctly if:
                // 1. There is a single udta for the entire file
                //   - OR -
                // 2. There are multiple utdtas, but only 1 of them contains the Apple ILST box.
                // We should be OK in the vast majority of cases
                IsoUserDataBox udtaBox = FindAppleTagUdta();
                if (null == udtaBox)
                {
                    udtaBox = new IsoUserDataBox();
                }
                ByteVector tag_data = udtaBox.Render();

                // If we don't have a "udta" box to overwrite...
                if (udtaBox.ParentTree == null ||
                    udtaBox.ParentTree.Length == 0)
                {
                    // Stick the box at the end of the moov box.
                    BoxHeader moov_header = parser.MoovTree[
                        parser.MoovTree.Length - 1];
                    size_change    = tag_data.Count;
                    write_position = moov_header.Position +
                                     moov_header.TotalBoxSize;
                    Insert(tag_data, write_position, 0);

                    // Overwrite the parent box sizes.
                    for (int i = parser.MoovTree.Length - 1; i >= 0;
                         i--)
                    {
                        size_change = parser.MoovTree[i
                                      ].Overwrite(this, size_change);
                    }
                }
                else
                {
                    // Overwrite the old box.
                    BoxHeader udta_header = udtaBox.ParentTree[udtaBox.ParentTree.Length - 1];
                    size_change = tag_data.Count -
                                  udta_header.TotalBoxSize;
                    write_position = udta_header.Position;
                    Insert(tag_data, write_position,
                           udta_header.TotalBoxSize);

                    // Overwrite the parent box sizes.
                    for (int i = udtaBox.ParentTree.Length - 2; i >= 0;
                         i--)
                    {
                        size_change = udtaBox.ParentTree[i
                                      ].Overwrite(this, size_change);
                    }
                }

                // If we've had a size change, we may need to adjust
                // chunk offsets.
                if (size_change != 0)
                {
                    // We may have moved the offset boxes, so we
                    // need to reread.
                    parser.ParseChunkOffsets();
                    InvariantStartPosition = parser.MdatStartPosition;
                    InvariantEndPosition   = parser.MdatEndPosition;

                    foreach (Box box in parser.ChunkOffsetBoxes)
                    {
                        IsoChunkLargeOffsetBox co64 =
                            box as IsoChunkLargeOffsetBox;

                        if (co64 != null)
                        {
                            co64.Overwrite(this,
                                           size_change,
                                           write_position);
                            continue;
                        }

                        IsoChunkOffsetBox stco =
                            box as IsoChunkOffsetBox;

                        if (stco != null)
                        {
                            stco.Overwrite(this,
                                           size_change,
                                           write_position);
                            continue;
                        }
                    }
                }

                TagTypesOnDisk = TagTypes;
            }
            finally
            {
                Mode = File.AccessMode.Closed;
            }
        }