示例#1
0
        public virtual bool Remove(BinaryWriter w)
        {
            bool result          = true;
            long cumulativeDelta = 0;

            if (embedder != null && getImplementedTagType() == MetaDataIOFactory.TAG_ID3V2)
            {
                structureHelper.Clear();
                structureHelper.AddZone(embedder.Id3v2Zone);
            }

            foreach (Zone zone in Zones)
            {
                if (zone.Offset > -1 && !zone.Name.Equals(PADDING_ZONE_NAME))
                {
                    if (zone.IsDeletable)
                    {
                        if (zone.Size > zone.CoreSignature.Length)
                        {
                            StreamUtils.ShortenStream(w.BaseStream, zone.Offset + zone.Size - cumulativeDelta, (uint)(zone.Size - zone.CoreSignature.Length));
                        }

                        if (zone.CoreSignature.Length > 0)
                        {
                            w.BaseStream.Position = zone.Offset - cumulativeDelta;
                            w.Write(zone.CoreSignature);
                        }
                    }
                    if (MetaDataIOFactory.TAG_NATIVE == getImplementedTagType() || (embedder != null && getImplementedTagType() == MetaDataIOFactory.TAG_ID3V2))
                    {
                        if (zone.IsDeletable)
                        {
                            result = result && structureHelper.RewriteHeaders(w, null, -zone.Size + zone.CoreSignature.Length, ACTION.Delete, zone.Name);
                        }
                        else
                        {
                            result = result && structureHelper.RewriteHeaders(w, null, 0, ACTION.Edit, zone.Name);
                        }
                    }

                    if (zone.IsDeletable)
                    {
                        cumulativeDelta += zone.Size - zone.CoreSignature.Length;
                    }
                }
            }

            return(result);
        }
        public void FSH_Edit()
        {
            using (Stream s = new MemoryStream())
                using (BinaryWriter w = new BinaryWriter(s))
                    using (BinaryReader r = new BinaryReader(s))
                    {
                        init(w);

                        StreamUtils.ShortenStream(s, 18, 2);
                        structureHelper.RewriteHeaders(w, -2, FileStructureHelper.ACTION.Edit, "zone1");

                        r.BaseStream.Seek(0, SeekOrigin.Begin);
                        Assert.AreEqual((ulong)8, r.ReadUInt64());

                        r.BaseStream.Seek(8, SeekOrigin.Begin);
                        Assert.AreEqual((byte)2, r.ReadByte());

                        r.BaseStream.Seek(9, SeekOrigin.Begin);
                        Assert.AreEqual((uint)3, r.ReadUInt32());

                        r.BaseStream.Seek(16, SeekOrigin.Begin);
                        Assert.AreEqual((uint)5, r.ReadUInt32());


                        StreamUtils.ShortenStream(s, 25, 2);
                        structureHelper.RewriteHeaders(w, -2, FileStructureHelper.ACTION.Edit, "zone2");

                        r.BaseStream.Seek(0, SeekOrigin.Begin);
                        Assert.AreEqual((ulong)6, r.ReadUInt64());

                        r.BaseStream.Seek(8, SeekOrigin.Begin);
                        Assert.AreEqual((byte)2, r.ReadByte());

                        r.BaseStream.Seek(9, SeekOrigin.Begin);
                        Assert.AreEqual((uint)3, r.ReadUInt32());

                        r.BaseStream.Seek(16, SeekOrigin.Begin);
                        Assert.AreEqual((uint)3, r.ReadUInt32());
                    }
        }
示例#3
0
        public bool Write(BinaryReader r, BinaryWriter w, TagData tag)
        {
            long oldTagSize;
            long newTagSize;
            long cumulativeDelta = 0;
            bool result          = true;

            // Constraint-check on non-supported values
            if (FieldCodeFixedLength > 0)
            {
                if (tag.Pictures != null)
                {
                    foreach (PictureInfo picInfo in tag.Pictures)
                    {
                        if (PictureInfo.PIC_TYPE.Unsupported.Equals(picInfo.PicType) && (picInfo.TagType.Equals(getImplementedTagType())))
                        {
                            if ((-1 == picInfo.NativePicCode) && (Utils.ProtectValue(picInfo.NativePicCodeStr).Length != FieldCodeFixedLength))
                            {
                                throw new NotSupportedException("Field code fixed length is " + FieldCodeFixedLength + "; detected field '" + Utils.ProtectValue(picInfo.NativePicCodeStr) + "' is " + Utils.ProtectValue(picInfo.NativePicCodeStr).Length + " characters long and cannot be written");
                            }
                        }
                    }
                }
                foreach (MetaFieldInfo fieldInfo in tag.AdditionalFields)
                {
                    if (fieldInfo.TagType.Equals(getImplementedTagType()) || MetaDataIOFactory.TAG_ANY == fieldInfo.TagType)
                    {
                        if (Utils.ProtectValue(fieldInfo.NativeFieldCode).Length != FieldCodeFixedLength)
                        {
                            throw new NotSupportedException("Field code fixed length is " + FieldCodeFixedLength + "; detected field '" + Utils.ProtectValue(fieldInfo.NativeFieldCode) + "' is " + Utils.ProtectValue(fieldInfo.NativeFieldCode).Length + " characters long and cannot be written");
                        }
                    }
                }
            }

            structureHelper.Clear();
            tagData.Pictures.Clear();

            // Read all the fields in the existing tag (including unsupported fields)
            ReadTagParams readTagParams = new ReadTagParams(true, true);

            readTagParams.PrepareForWriting = true;

            if (embedder != null && embedder.HasEmbeddedID3v2 > 0)
            {
                readTagParams.offset = embedder.HasEmbeddedID3v2;
            }

            this.read(r, readTagParams);

            if (embedder != null && getImplementedTagType() == MetaDataIOFactory.TAG_ID3V2)
            {
                structureHelper.Clear();
                structureHelper.AddZone(embedder.Id3v2Zone);
            }

            // Give engine something to work with if the tag is really empty
            if (!tagExists && 0 == Zones.Count)
            {
                structureHelper.AddZone(0, 0);
            }

            TagData dataToWrite;

            dataToWrite = tagData;
            dataToWrite.IntegrateValues(tag); // Merge existing information + new tag information

            foreach (Zone zone in Zones)
            {
                oldTagSize = zone.Size;
                bool isTagWritten;

                // Write new tag to a MemoryStream
                using (MemoryStream s = new MemoryStream(zone.Size))
                    using (BinaryWriter msw = new BinaryWriter(s, Settings.DefaultTextEncoding))
                    {
                        if (write(dataToWrite, msw, zone.Name) > 0)
                        {
                            isTagWritten = true;
                            newTagSize   = s.Length;

                            if (embedder != null && getImplementedTagType() == MetaDataIOFactory.TAG_ID3V2 && embedder.ID3v2EmbeddingHeaderSize > 0)
                            {
                                StreamUtils.LengthenStream(s, 0, embedder.ID3v2EmbeddingHeaderSize);
                                s.Position = 0;
                                embedder.WriteID3v2EmbeddingHeader(msw, newTagSize);

                                newTagSize = s.Length;
                            }
                        }
                        else
                        {
                            isTagWritten = false;
                            newTagSize   = zone.CoreSignature.Length;
                        }

                        // -- Adjust tag slot to new size in file --
                        long tagBeginOffset, tagEndOffset;

                        if (tagExists && zone.Size > zone.CoreSignature.Length) // An existing tag has been reprocessed
                        {
                            tagBeginOffset = zone.Offset + cumulativeDelta;
                            tagEndOffset   = tagBeginOffset + zone.Size;
                        }
                        else // A brand new tag has been added to the file
                        {
                            if (embedder != null && getImplementedTagType() == MetaDataIOFactory.TAG_ID3V2)
                            {
                                tagBeginOffset = embedder.Id3v2Zone.Offset;
                            }
                            else
                            {
                                switch (getDefaultTagOffset())
                                {
                                case TO_EOF: tagBeginOffset = r.BaseStream.Length; break;

                                case TO_BOF: tagBeginOffset = 0; break;

                                case TO_BUILTIN: tagBeginOffset = zone.Offset + cumulativeDelta; break;

                                default: tagBeginOffset = -1; break;
                                }
                            }
                            tagEndOffset = tagBeginOffset + zone.Size;
                        }

                        // Need to build a larger file
                        if (newTagSize > zone.Size)
                        {
                            StreamUtils.LengthenStream(w.BaseStream, tagEndOffset, (uint)(newTagSize - zone.Size));
                        }
                        else if (newTagSize < zone.Size) // Need to reduce file size
                        {
                            StreamUtils.ShortenStream(w.BaseStream, tagEndOffset, (uint)(zone.Size - newTagSize));
                        }

                        // Copy tag contents to the new slot
                        r.BaseStream.Seek(tagBeginOffset, SeekOrigin.Begin);
                        s.Seek(0, SeekOrigin.Begin);

                        if (isTagWritten)
                        {
                            StreamUtils.CopyStream(s, w.BaseStream);
                        }
                        else
                        {
                            if (zone.CoreSignature.Length > 0)
                            {
                                msw.Write(zone.CoreSignature);
                            }
                        }

                        int delta = (int)(newTagSize - oldTagSize);
                        cumulativeDelta += delta;

                        // Edit wrapping size markers and frame counters if needed
                        if (delta != 0 && (MetaDataIOFactory.TAG_NATIVE == getImplementedTagType() || (embedder != null && getImplementedTagType() == MetaDataIOFactory.TAG_ID3V2)))
                        {
                            int action;

                            if (oldTagSize == zone.CoreSignature.Length && isTagWritten)
                            {
                                action = ACTION_ADD;
                            }
                            else if (newTagSize == zone.CoreSignature.Length && !isTagWritten)
                            {
                                action = ACTION_DELETE;
                            }
                            else
                            {
                                action = ACTION_EDIT;
                            }

                            result = structureHelper.RewriteHeaders(w, delta, action, zone.Name);
                        }
                    }
            } // Loop through zones

            // Update tag information without calling Read

            /* TODO - this implementation is too risky :
             *   - if one of the writing operations fails, data is updated as if everything went right
             *   - any picture slot with a markForDeletion flag is recorded as-is in the tag
             */
            tagData = dataToWrite;

            return(result);
        }
示例#4
0
        private bool RewriteZonesDirect(
            BinaryWriter w,
            WriteDelegate write,
            ICollection <Zone> zones,
            TagData dataToWrite,
            bool tagExists,
            long globalOffsetCorrection = 0,
            bool buffered = false)
        {
            long oldTagSize;
            long newTagSize;
            long cumulativeDelta = 0;
            bool result          = true;

            //            totalProgressSteps += zones.Count;
            foreach (Zone zone in zones)
            {
                oldTagSize = zone.Size;

                // Write new tag to a MemoryStream
                using (MemoryStream s = new MemoryStream(zone.Size))
                    using (BinaryWriter msw = new BinaryWriter(s, Settings.DefaultTextEncoding))
                    {
                        dataToWrite.DataSizeDelta = cumulativeDelta;
                        WriteResult writeResult = write(msw, dataToWrite, zone);

                        if (WriteMode.REPLACE == writeResult.RequiredMode)
                        {
                            if (writeResult.WrittenFields > 0)
                            {
                                newTagSize = s.Length;

                                if (embedder != null && implementedTagType == MetaDataIOFactory.TAG_ID3V2 && embedder.ID3v2EmbeddingHeaderSize > 0)
                                {
                                    StreamUtils.LengthenStream(s, 0, embedder.ID3v2EmbeddingHeaderSize);
                                    s.Position = 0;
                                    embedder.WriteID3v2EmbeddingHeader(msw, newTagSize);

                                    newTagSize = s.Length;
                                }
                            }
                            else
                            {
                                newTagSize = zone.CoreSignature.Length;
                            }
                        }
                        else // Overwrite mode
                        {
                            newTagSize = zone.Size;
                        }

                        // -- Adjust tag slot to new size in file --
                        long tagBeginOffset, tagEndOffset;

                        if (tagExists && zone.Size > zone.CoreSignature.Length) // An existing tag has been reprocessed
                        {
                            tagBeginOffset = zone.Offset + cumulativeDelta - globalOffsetCorrection;
                            tagEndOffset   = tagBeginOffset + zone.Size;
                        }
                        else // A brand new tag has been added to the file
                        {
                            if (embedder != null && implementedTagType == MetaDataIOFactory.TAG_ID3V2)
                            {
                                tagBeginOffset = embedder.Id3v2Zone.Offset - globalOffsetCorrection;
                            }
                            else
                            {
                                switch (defaultTagOffset)
                                {
                                case MetaDataIO.TO_EOF: tagBeginOffset = w.BaseStream.Length; break;

                                case MetaDataIO.TO_BOF: tagBeginOffset = 0; break;

                                case MetaDataIO.TO_BUILTIN: tagBeginOffset = zone.Offset + cumulativeDelta; break;

                                default: tagBeginOffset = -1; break;
                                }
                                tagBeginOffset -= globalOffsetCorrection;
                            }
                            tagEndOffset = tagBeginOffset + zone.Size;
                        }

                        if (WriteMode.REPLACE == writeResult.RequiredMode)
                        {
                            // Need to build a larger file
                            if (newTagSize > zone.Size)
                            {
                                if (!buffered)
                                {
                                    Logging.LogDelegator.GetLogDelegate()(Logging.Log.LV_DEBUG, "Disk stream operation : Lengthening (delta=" + (newTagSize - zone.Size) + ")");
                                }
                                StreamUtils.LengthenStream(w.BaseStream, tagEndOffset, (uint)(newTagSize - zone.Size));
                            }
                            else if (newTagSize < zone.Size) // Need to reduce file size
                            {
                                if (!buffered)
                                {
                                    Logging.LogDelegator.GetLogDelegate()(Logging.Log.LV_DEBUG, "Disk stream operation : Shortening (delta=" + (newTagSize - zone.Size) + ")");
                                }
                                StreamUtils.ShortenStream(w.BaseStream, tagEndOffset, (uint)(zone.Size - newTagSize));
                            }
                        }

                        // Copy tag contents to the new slot
                        w.BaseStream.Seek(tagBeginOffset, SeekOrigin.Begin);
                        s.Seek(0, SeekOrigin.Begin);

                        if (writeResult.WrittenFields > 0)
                        {
                            StreamUtils.CopyStream(s, w.BaseStream);
                        }
                        else
                        {
                            if (zone.CoreSignature.Length > 0)
                            {
                                msw.Write(zone.CoreSignature);
                            }
                        }

                        long delta = newTagSize - oldTagSize;
                        cumulativeDelta += delta;

                        // Edit wrapping size markers and frame counters if needed
                        if (structureHelper != null && (MetaDataIOFactory.TAG_NATIVE == implementedTagType || (embedder != null && implementedTagType == MetaDataIOFactory.TAG_ID3V2)))
                        {
                            ACTION action;
                            bool   isTagWritten = (writeResult.WrittenFields > 0);

                            if (0 == delta)
                            {
                                action = ACTION.Edit;         // Zone content has not changed; headers might need to be rewritten (e.g. offset changed)
                            }
                            else
                            {
                                if (oldTagSize == zone.CoreSignature.Length && isTagWritten)
                                {
                                    action = ACTION.Add;
                                }
                                else if (newTagSize == zone.CoreSignature.Length && !isTagWritten)
                                {
                                    action = ACTION.Delete;
                                }
                                else
                                {
                                    action = ACTION.Edit;
                                }
                            }

                            result = structureHelper.RewriteHeaders(w, delta, action, zone.Name, globalOffsetCorrection);
                        }

                        zone.Size = (int)newTagSize;
                    }
                //                if (writeProgress != null) writeProgress.Report(++currentProgress / totalProgressSteps);
            } // Loop through zones

            return(result);
        }
示例#5
0
        /// <summary>
        /// Rewrites zones that have to be rewritten
        ///     - Works region after region, buffering them if needed
        ///     - Put each zone into memory and update them using the given WriteDelegate
        ///     - Adjust file size and region headers accordingly
        /// </summary>
        /// <param name="fullScopeWriter">BinaryWriter opened on the data stream (usually, contents of an audio file) to be rewritten</param>
        /// <param name="write">Delegate to the write method of the <see cref="IMetaDataIO"/> to be used to update the data stream</param>
        /// <param name="zones">Zones to rewrite</param>
        /// <param name="dataToWrite">Metadata to update the zones with</param>
        /// <param name="tagExists">True if the tag already exists on the current data stream; false if not</param>
        /// <param name="useBuffer">True if I/O has to be buffered. Makes I/O faster but consumes more RAM.</param>
        /// <returns>True if the operation succeeded; false if it something unexpected happened during the processing</returns>
        private bool RewriteZones(
            BinaryWriter fullScopeWriter,
            WriteDelegate write,
            ICollection <Zone> zones,
            TagData dataToWrite,
            bool tagExists,
            bool useBuffer)
        {
            long oldTagSize;
            long newTagSize;
            long globalOffsetCorrection;
            long globalCumulativeDelta = 0;
            bool result     = true;
            bool isBuffered = false;

            IList <ZoneRegion> zoneRegions = computeZoneRegions(zones, fullScopeWriter.BaseStream.Length);
            BinaryWriter       writer;

            Logging.LogDelegator.GetLogDelegate()(Logging.Log.LV_DEBUG, "========================================");
            Logging.LogDelegator.GetLogDelegate()(Logging.Log.LV_DEBUG, "Found " + zoneRegions.Count + " regions");
            foreach (ZoneRegion region in zoneRegions)
            {
                Logging.LogDelegator.GetLogDelegate()(Logging.Log.LV_DEBUG, region.ToString());
            }
            Logging.LogDelegator.GetLogDelegate()(Logging.Log.LV_DEBUG, "========================================");

            int regionIndex = 0;

            foreach (ZoneRegion region in zoneRegions)
            {
                long regionCumulativeDelta = 0;
                Logging.LogDelegator.GetLogDelegate()(Logging.Log.LV_DEBUG, "------------ REGION " + regionIndex++);

                int          initialBufferSize = region.Size;
                MemoryStream buffer            = null;
                try
                {
                    if (useBuffer && region.IsBufferable)
                    {
                        isBuffered = true;
                        Logging.LogDelegator.GetLogDelegate()(Logging.Log.LV_DEBUG, "Buffering " + Utils.GetBytesReadable(initialBufferSize));
                        buffer = new MemoryStream(initialBufferSize);

                        // Copy file data to buffer
                        if (initialBufferSize > 0)
                        {
                            if (structureHelper != null)
                            {
                                fullScopeWriter.BaseStream.Seek(structureHelper.getCorrectedOffset(region.StartOffset), SeekOrigin.Begin);
                            }
                            else // for classes that don't use FileStructureHelper(FLAC)
                            {
                                fullScopeWriter.BaseStream.Seek(region.StartOffset + globalCumulativeDelta, SeekOrigin.Begin);
                            }

                            StreamUtils.CopyStream(fullScopeWriter.BaseStream, buffer, initialBufferSize);
                        }

                        writer = new BinaryWriter(buffer, Settings.DefaultTextEncoding);
                        globalOffsetCorrection = region.StartOffset;
                    }
                    else
                    {
                        isBuffered             = false;
                        writer                 = fullScopeWriter;
                        globalOffsetCorrection = 0;
                    }

                    foreach (Zone zone in region.Zones)
                    {
                        oldTagSize = zone.Size;

                        Logging.LogDelegator.GetLogDelegate()(Logging.Log.LV_DEBUG, "------ ZONE " + zone.Name + "@" + zone.Offset);
                        Logging.LogDelegator.GetLogDelegate()(Logging.Log.LV_DEBUG, "Allocating " + Utils.GetBytesReadable(zone.Size));

                        // Write new tag to a MemoryStream
                        using (MemoryStream s = new MemoryStream(zone.Size))
                            using (BinaryWriter msw = new BinaryWriter(s, Settings.DefaultTextEncoding))
                            {
                                // DataSizeDelta needs to be incremented to be used by classes that don't use FileStructureHelper (e.g. FLAC)
                                dataToWrite.DataSizeDelta = globalCumulativeDelta;
                                WriteResult writeResult = write(msw, dataToWrite, zone);

                                if (WriteMode.REPLACE == writeResult.RequiredMode)
                                {
                                    if (writeResult.WrittenFields > 0)
                                    {
                                        newTagSize = s.Length;

                                        if (embedder != null && implementedTagType == MetaDataIOFactory.TAG_ID3V2 && embedder.ID3v2EmbeddingHeaderSize > 0)
                                        {
                                            StreamUtils.LengthenStream(s, 0, embedder.ID3v2EmbeddingHeaderSize);
                                            s.Position = 0;
                                            embedder.WriteID3v2EmbeddingHeader(msw, newTagSize);

                                            newTagSize = s.Length;
                                        }
                                    }
                                    else
                                    {
                                        newTagSize = zone.CoreSignature.Length;
                                    }
                                }
                                else // Overwrite mode
                                {
                                    newTagSize = zone.Size;
                                }

                                Logging.LogDelegator.GetLogDelegate()(Logging.Log.LV_DEBUG, "newTagSize : " + Utils.GetBytesReadable(newTagSize));

                                // -- Adjust tag slot to new size in file --
                                long tagBeginOffset, tagEndOffset;

                                if (tagExists && zone.Size > zone.CoreSignature.Length) // An existing tag has been reprocessed
                                {
                                    tagBeginOffset = zone.Offset + (isBuffered ? regionCumulativeDelta : globalCumulativeDelta) - globalOffsetCorrection;
                                    tagEndOffset   = tagBeginOffset + zone.Size;
                                }
                                else // A brand new tag has been added to the file
                                {
                                    if (embedder != null && implementedTagType == MetaDataIOFactory.TAG_ID3V2)
                                    {
                                        tagBeginOffset = embedder.Id3v2Zone.Offset - globalOffsetCorrection;
                                    }
                                    else
                                    {
                                        switch (defaultTagOffset)
                                        {
                                        case MetaDataIO.TO_EOF: tagBeginOffset = writer.BaseStream.Length; break;

                                        case MetaDataIO.TO_BOF: tagBeginOffset = 0; break;

                                        case MetaDataIO.TO_BUILTIN: tagBeginOffset = zone.Offset + (isBuffered ? regionCumulativeDelta : globalCumulativeDelta); break;

                                        default: tagBeginOffset = -1; break;
                                        }
                                        tagBeginOffset -= globalOffsetCorrection;
                                    }
                                    tagEndOffset = tagBeginOffset + zone.Size;
                                }

                                if (WriteMode.REPLACE == writeResult.RequiredMode)
                                {
                                    // Need to build a larger file
                                    if (newTagSize > zone.Size)
                                    {
                                        uint deltaBytes = (uint)(newTagSize - zone.Size);
                                        if (!useBuffer)
                                        {
                                            Logging.LogDelegator.GetLogDelegate()(Logging.Log.LV_DEBUG, "Disk stream operation (direct) : Lengthening (delta=" + Utils.GetBytesReadable(deltaBytes) + ")");
                                        }
                                        else
                                        {
                                            Logging.LogDelegator.GetLogDelegate()(Logging.Log.LV_DEBUG, "Buffer stream operation : Lengthening (delta=" + Utils.GetBytesReadable(deltaBytes) + ")");
                                        }

                                        StreamUtils.LengthenStream(writer.BaseStream, tagEndOffset, deltaBytes);
                                    }
                                    else if (newTagSize < zone.Size) // Need to reduce file size
                                    {
                                        uint deltaBytes = (uint)(zone.Size - newTagSize);
                                        if (!useBuffer)
                                        {
                                            Logging.LogDelegator.GetLogDelegate()(Logging.Log.LV_DEBUG, "Disk stream operation (direct) : Shortening (delta=-" + Utils.GetBytesReadable(deltaBytes) + ")");
                                        }
                                        else
                                        {
                                            Logging.LogDelegator.GetLogDelegate()(Logging.Log.LV_DEBUG, "Buffer stream operation : Shortening (delta=-" + Utils.GetBytesReadable(deltaBytes) + ")");
                                        }

                                        StreamUtils.ShortenStream(writer.BaseStream, tagEndOffset, deltaBytes);
                                    }
                                }

                                // Copy tag contents to the new slot
                                writer.BaseStream.Seek(tagBeginOffset, SeekOrigin.Begin);
                                s.Seek(0, SeekOrigin.Begin);

                                if (writeResult.WrittenFields > 0)
                                {
                                    StreamUtils.CopyStream(s, writer.BaseStream);
                                }
                                else
                                {
                                    if (zone.CoreSignature.Length > 0)
                                    {
                                        msw.Write(zone.CoreSignature);
                                    }
                                }

                                long delta = newTagSize - oldTagSize;
                                regionCumulativeDelta += delta;
                                globalCumulativeDelta += delta;

                                // Edit wrapping size markers and frame counters if needed
                                if (structureHelper != null && (MetaDataIOFactory.TAG_NATIVE == implementedTagType || (embedder != null && implementedTagType == MetaDataIOFactory.TAG_ID3V2)))
                                {
                                    ACTION action;
                                    bool   isTagWritten = (writeResult.WrittenFields > 0);

                                    if (0 == delta)
                                    {
                                        action = ACTION.Edit;         // Zone content has not changed; headers might need to be rewritten (e.g. offset changed)
                                    }
                                    else
                                    {
                                        if (oldTagSize == zone.CoreSignature.Length && isTagWritten)
                                        {
                                            action = ACTION.Add;
                                        }
                                        else if (newTagSize == zone.CoreSignature.Length && !isTagWritten)
                                        {
                                            action = ACTION.Delete;
                                        }
                                        else
                                        {
                                            action = ACTION.Edit;
                                        }
                                    }
                                    // Use plain writer here on purpose because its zone contains headers for the zones adressed by the static writer
                                    result &= structureHelper.RewriteHeaders(fullScopeWriter, isBuffered ? writer : null, delta, action, zone.Name, globalOffsetCorrection, isBuffered ? region.Id : -1);
                                }

                                zone.Size = (int)newTagSize;
                            }// MemoryStream used to process current zone
                    } // Loop through zones

                    if (buffer != null)
                    {
                        // -- Adjust file slot to new size of buffer --
                        long tagEndOffset = region.StartOffset + initialBufferSize;

                        // Need to build a larger file
                        if (buffer.Length > initialBufferSize)
                        {
                            Logging.LogDelegator.GetLogDelegate()(Logging.Log.LV_DEBUG, "Disk stream operation (buffer) : Lengthening (delta=" + Utils.GetBytesReadable(buffer.Length - initialBufferSize) + ")");
                            StreamUtils.LengthenStream(fullScopeWriter.BaseStream, tagEndOffset, (uint)(buffer.Length - initialBufferSize));
                        }
                        else if (buffer.Length < initialBufferSize) // Need to reduce file size
                        {
                            Logging.LogDelegator.GetLogDelegate()(Logging.Log.LV_DEBUG, "Disk stream operation (buffer) : Shortening (delta=" + Utils.GetBytesReadable(buffer.Length - initialBufferSize) + ")");
                            StreamUtils.ShortenStream(fullScopeWriter.BaseStream, tagEndOffset, (uint)(initialBufferSize - buffer.Length));
                        }

                        // Copy tag contents to the new slot
                        fullScopeWriter.BaseStream.Seek(region.StartOffset, SeekOrigin.Begin);
                        buffer.Seek(0, SeekOrigin.Begin);

                        StreamUtils.CopyStream(buffer, fullScopeWriter.BaseStream);
                    }
                }
                finally // Make sure buffers are properly disallocated
                {
                    if (buffer != null)
                    {
                        buffer.Close();
                        buffer = null;
                    }
                }

                Logging.LogDelegator.GetLogDelegate()(Logging.Log.LV_DEBUG, "");
            } // Loop through zone regions

            // Post-processing changes
            if (structureHelper != null && structureHelper.ZoneNames.Contains(FileStructureHelper.POST_PROCESSING_ZONE_NAME))
            {
                Logging.LogDelegator.GetLogDelegate()(Logging.Log.LV_DEBUG, "Post-processing");
                structureHelper.PostProcessing(fullScopeWriter);
            }

            return(result);
        }