// NB : This only works if writeVorbisTag is called _before_ writePictures, since tagData fusion is done by vorbisTag.Write public bool Write(BinaryReader r, BinaryWriter w, TagData tag) { // Read all the fields in the existing tag (including unsupported fields) ReadTagParams readTagParams = new ReadTagParams(true, true); readTagParams.PrepareForWriting = true; bool tagExists = Read(r, readTagParams); // Save a snapshot of the initial embedded pictures for processing purposes existingPictureIndex = 0; targetPictureIndex = 0; initialPictures = vorbisTag.EmbeddedPictures; // Prepare picture data with freshly read vorbisTag TagData dataToWrite = new TagData(); dataToWrite.Pictures = vorbisTag.EmbeddedPictures; dataToWrite.IntegrateValues(tag, true, false); // Merge existing information + new tag information except additional fields which will be merged by VorbisComment adjustPictureZones(dataToWrite.Pictures); FileSurgeon surgeon = new FileSurgeon(null, null, MetaDataIOFactory.TAG_NATIVE, TO_BUILTIN); surgeon.RewriteZones(w, new WriteDelegate(write), zones, dataToWrite, tagExists); // Set the 'isLast' bit on the actual last block w.BaseStream.Seek(latestBlockOffset, SeekOrigin.Begin); w.Write((byte)(latestBlockType | FLAG_LAST_METADATA_BLOCK)); return(true); }
public bool Write(BinaryReader r, BinaryWriter w, TagData tag) { 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) { string fieldCode = Utils.ProtectValue(fieldInfo.NativeFieldCode); if (fieldCode.Length != FieldCodeFixedLength && !fieldCode.Contains("----")) // "----" = exception for MP4 extended fields (e.g. ----:com.apple.iTunes:CONDUCTOR) { throw new NotSupportedException("Field code fixed length is " + FieldCodeFixedLength + "; detected field '" + fieldCode + "' is " + fieldCode.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 dataToWrite.Cleanup(); FileSurgeon surgeon = new FileSurgeon(structureHelper, embedder, getImplementedTagType(), getDefaultTagOffset()); result = surgeon.RewriteZones(w, new FileSurgeon.WriteDelegate(writeAdapter), Zones, dataToWrite, tagExists); // 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); }