Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/Id3.Net/Id3/Id3Handler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ internal string GetFrameIdFromFrame(Id3Frame frame)
internal abstract byte[] GetTagBytes(Stream stream);
internal abstract bool HasTag(Stream stream);
internal abstract Id3Tag ReadTag(Stream stream, out object additionalData);
internal abstract bool WriteTag(Stream stream, Id3Tag tag);
internal abstract bool WriteTag(Stream stream, Id3Tag tag, WriteTagOptions options);
#endregion

#region ID3 tag properties for the handler
Expand Down
2 changes: 1 addition & 1 deletion src/Id3.Net/Id3/v1/Id3v1Handler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ internal override Id3Tag ReadTag(Stream stream, out object additionalData)
return tag;
}

internal override bool WriteTag(Stream stream, Id3Tag tag)
internal override bool WriteTag(Stream stream, Id3Tag tag, WriteTagOptions options)
{
Encoding encoding = TextEncodingHelper.GetDefaultEncoding();

Expand Down
47 changes: 43 additions & 4 deletions src/Id3.Net/Id3/v2/Id3v23Handler.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#region --- License & Copyright Notice ---
#region --- License & Copyright Notice ---
/*
Copyright (c) 2005-2019 Jeevan James
All rights reserved.
Expand Down Expand Up @@ -156,7 +156,7 @@ internal override Id3Tag ReadTag(Stream stream, out object additionalData)
return tag;
}

internal override bool WriteTag(Stream stream, Id3Tag tag)
internal override bool WriteTag(Stream stream, Id3Tag tag, WriteTagOptions options)
{
byte[] tagBytes = GetTagBytes(tag);
int requiredTagSize = tagBytes.Length;
Expand All @@ -165,7 +165,13 @@ internal override bool WriteTag(Stream stream, Id3Tag tag)
int currentTagSize = GetTagSize(stream);
if (requiredTagSize > currentTagSize)
MakeSpaceForTag(stream, currentTagSize, requiredTagSize);
} else
else if (requiredTagSize < currentTagSize)
if (options.ShrinkFile && (currentTagSize - requiredTagSize) > options.ShrinkFileThreshold)
ShrinkSpaceForTag(stream, currentTagSize, requiredTagSize);
else if (options.WipeOut)
WipeOutRemainingSpace(stream, currentTagSize, requiredTagSize);
}
else
MakeSpaceForTag(stream, 0, requiredTagSize);

stream.Seek(0, SeekOrigin.Begin);
Expand Down Expand Up @@ -310,6 +316,39 @@ private static void MakeSpaceForTag(Stream stream, int currentTagSize, int requi
}
}

private const int BufferSize = 8192;
private static void ShrinkSpaceForTag(Stream stream, int currentTagSize, int requiredTagSize)
{
if (currentTagSize < requiredTagSize)
return;

int streamLength = (int)stream.Length;
var readPos = currentTagSize;
int writePos = requiredTagSize;

var buffer = new byte[BufferSize];
while (readPos < streamLength)
{
int bytesToRead = (readPos + BufferSize > streamLength) ? streamLength - readPos : BufferSize;
stream.Seek(readPos, SeekOrigin.Begin);
stream.Read(buffer, 0, bytesToRead);
stream.Seek(writePos, SeekOrigin.Begin);
stream.Write(buffer, 0, bytesToRead);
readPos += bytesToRead;
writePos += bytesToRead;
}
stream.SetLength(writePos);
}

private static void WipeOutRemainingSpace(Stream stream, int currentTagSize, int requiredTagSize)
{
if (currentTagSize < requiredTagSize)
return;

var remainingSize = currentTagSize - requiredTagSize;
stream.Seek(requiredTagSize, SeekOrigin.Begin);
stream.Write(new byte[remainingSize], 0, remainingSize);
}

private const int BufferSize = 512 * 1024; // 8192 - memory is no big issue today, so reduce the seeking efforts
}
}
31 changes: 20 additions & 11 deletions src/Id3.Net/Mp3/Mp3.cs
Original file line number Diff line number Diff line change
Expand Up @@ -272,10 +272,26 @@ public bool HasTagOfVersion(Id3Version version) =>
#region Tag writing methods
public bool UpdateTag(Id3Tag tag)
{
return WriteTag(tag, WriteConflictAction.Replace);
return WriteTag(tag, new WriteTagOptions() { ConflictAction = WriteConflictAction.Replace });
}

public bool WriteTag(Id3Tag tag, WriteConflictAction conflictAction = WriteConflictAction.NoAction)
{
return WriteTag(tag, new WriteTagOptions() { ConflictAction = conflictAction });
}

public bool WriteTag(Id3Tag tag, Id3Version version, WriteConflictAction conflictAction = WriteConflictAction.NoAction)
{
return WriteTag(tag, version, new WriteTagOptions() { ConflictAction = conflictAction });
}

public bool WriteTag(Id3Tag tag, Id3Version version, WriteTagOptions options)
{
tag.Version = version;
return WriteTag(tag, options);
}

public bool WriteTag(Id3Tag tag, WriteTagOptions options)
{
if (tag == null)
throw new ArgumentNullException(nameof(tag));
Expand All @@ -290,9 +306,9 @@ public bool WriteTag(Id3Tag tag, WriteConflictAction conflictAction = WriteConfl
Id3Handler handler = familyHandler;
if (handler.Version != tag.Version)
{
if (conflictAction == WriteConflictAction.NoAction)
if (options.ConflictAction == WriteConflictAction.NoAction)
return false;
if (conflictAction == WriteConflictAction.Replace)
if (options.ConflictAction == WriteConflictAction.Replace)
{
Id3Handler handlerCopy = handler; //TODO: Why did we need a copy of the handler?
handlerCopy.DeleteTag(Stream);
Expand All @@ -302,18 +318,11 @@ public bool WriteTag(Id3Tag tag, WriteConflictAction conflictAction = WriteConfl

//Write the tag to the file. The handler will know how to overwrite itself.
Id3Handler writeHandler = Id3Handler.GetHandler(tag.Version);
bool writeSuccessful = writeHandler.WriteTag(Stream, tag);
bool writeSuccessful = writeHandler.WriteTag(Stream, tag, options);
if (writeSuccessful)
InvalidateExistingHandlers();
return writeSuccessful;
}

public bool WriteTag(Id3Tag tag, Id3Version version,
WriteConflictAction conflictAction = WriteConflictAction.NoAction)
{
tag.Version = version;
return WriteTag(tag, conflictAction);
}
#endregion

#region Audio stream members
Expand Down
17 changes: 17 additions & 0 deletions src/Id3.Net/Mp3/WriteTagOptions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Text;

namespace Id3
{
public class WriteTagOptions
{
public WriteConflictAction ConflictAction { get; set; } = WriteConflictAction.NoAction;

public bool WipeOut { get; set; } = true;

public bool ShrinkFile { get; set; } = true;

public int ShrinkFileThreshold { get; set; } = 0;
}
}