/// <summary> /// Writes the given metadata into the given stream using the ID3v1.1 standard /// NB : Metadata fields that are not supported by ID3v1.1 standard (e.g. Composer) won't be written into the stream, even though their value are set /// </summary> /// <param name="tag">Metadata to be written</param> /// <param name="w">Stream to be used</param> /// <returns>True if operation completed successfuly; else false</returns> protected override Int32 write(TagData tag, BinaryWriter w, String zone) { // ID3v1 tags are C-String(null-terminated)-based tags // they are not unicode-encoded, hence the use of ReadOneByteChars w.Write(ID3V1_ID.ToCharArray()); w.Write(Utils.BuildStrictLengthString(tag.Title, 30, '\0').ToCharArray()); w.Write(Utils.BuildStrictLengthString(tag.Artist, 30, '\0').ToCharArray()); w.Write(Utils.BuildStrictLengthString(tag.Album, 30, '\0').ToCharArray()); // ID3v1 standard requires the year w.Write(Utils.BuildStrictLengthString(TrackUtils.ExtractStrYear(tag.RecordingYear), 4, '\0').ToCharArray()); w.Write(Utils.BuildStrictLengthString(tag.Comment, 28, '\0').ToCharArray()); // ID3v1.1 standard w.Write('\0'); w.Write((Byte)Math.Min(TrackUtils.ExtractTrackNumber(tag.TrackNumber), Byte.MaxValue)); Byte genre = 0; if (tag.Genre != null) { for (Byte i = 0; i < MAX_MUSIC_GENRES; i++) { if (tag.Genre.ToUpper().Equals(MusicGenre[i].ToUpper())) { genre = i; break; } } } w.Write(genre); return(7); }
private void writeSubChunk(BinaryWriter writer, byte frameCode, string text) { writer.Write(frameCode); byte type = 1; if (extendedFrameTypes.ContainsKey(frameCode)) { type = extendedFrameTypes[frameCode]; } writer.Write(type); switch (type) { case XID6_TVAL: if (frameCode == XID6_TRACK) // Specific case : upper byte is the number 0-99, lower byte is an optional ASCII character { byte trackValue = (byte)Math.Min((ushort)0xFF, TrackUtils.ExtractTrackNumber(text)); writer.Write('\0'); // Optional char support is not implemented writer.Write(trackValue); } else { writer.Write(ushort.Parse(text)); // Value is directly written as an ushort into the length field } break; case XID6_TSTR: if (text.Length > 255) { text = text.Substring(0, 255); } else if (text.Length < 3) { text = Utils.BuildStrictLengthString(text, 3, ' '); } byte[] textBinary = Utils.Latin1Encoding.GetBytes(text); writer.Write((ushort)(textBinary.Length + 1)); writer.Write(textBinary); writer.Write('\0'); break; case XID6_TINT: writer.Write((ushort)4); writer.Write(Int32.Parse(text)); break; } }
public void TrackUtils_ExtractTrackNumber() { Assert.AreEqual(15, TrackUtils.ExtractTrackNumber("15")); Assert.AreEqual(15, TrackUtils.ExtractTrackNumber(" 15")); Assert.AreEqual(15, TrackUtils.ExtractTrackNumber(" 15 ")); Assert.AreEqual(15, TrackUtils.ExtractTrackNumber("15 ")); Assert.AreEqual(15, TrackUtils.ExtractTrackNumber("15.1")); Assert.AreEqual(15, TrackUtils.ExtractTrackNumber("15,1")); Assert.AreEqual(15, TrackUtils.ExtractTrackNumber("a15a")); Assert.AreEqual(0, TrackUtils.ExtractTrackNumber("")); Assert.AreEqual(0, TrackUtils.ExtractTrackNumber(null)); Assert.AreEqual(0, TrackUtils.ExtractTrackNumber("aaa")); Assert.AreEqual(0, TrackUtils.ExtractTrackNumber("99999999")); }
private void readHeaderTags(BinaryReader source, ref SPCHeader header, ReadTagParams readTagParams) { long initialPosition = source.BaseStream.Position; SetMetaField(HEADER_TITLE.ToString(), Utils.Latin1Encoding.GetString(source.ReadBytes(32)).Replace("\0", "").Trim(), readTagParams.ReadAllMetaFrames, ZONE_HEADER); SetMetaField(HEADER_ALBUM.ToString(), Utils.Latin1Encoding.GetString(source.ReadBytes(32)).Replace("\0", "").Trim(), readTagParams.ReadAllMetaFrames, ZONE_HEADER); SetMetaField(HEADER_DUMPERNAME.ToString(), Utils.Latin1Encoding.GetString(source.ReadBytes(16)).Replace("\0", "").Trim(), readTagParams.ReadAllMetaFrames, ZONE_HEADER); SetMetaField(HEADER_COMMENT.ToString(), Utils.Latin1Encoding.GetString(source.ReadBytes(32)).Replace("\0", "").Trim(), readTagParams.ReadAllMetaFrames, ZONE_HEADER); byte[] date, song, fade; // NB : Dump date is used to determine if the tag is binary or text-based. // It won't be recorded as a property of TSPC date = source.ReadBytes(11); song = source.ReadBytes(3); fade = source.ReadBytes(5); bool bin; int dateRes = isText(date); int songRes = isText(song); int fadeRes = isText(fade); //if ( 0 == (dateRes | songRes | fadeRes) ) // No time nor date -> use default //{ bin = true; //} //else if ((songRes != -1) && (fadeRes != -1)) // No time, or time is text { if (dateRes > 0) //If date is text, then tag is text { bin = false; } else if (0 == dateRes) //No date { bin = PREFER_BIN; //Times could still be binary (ex. 56 bin = '8' txt) } else if (-1 == dateRes) //Date contains invalid characters { bin = true; for (int i = 4; i < 8; i++) { bin = bin && (0 == date[i]); } } } else { bin = true; } int fadeVal; int songVal; if (bin) { fadeVal = fade[0] * 0x000001 + fade[1] * 0x0000FF + fade[2] * 0x00FF00 + fade[3] * 0xFF0000; if (fadeVal > 59999) { fadeVal = 59999; } songVal = song[0] * 0x01 + song[1] * 0x10; if (songVal > 959) { songVal = 959; } source.BaseStream.Seek(-1, SeekOrigin.Current); // We're one byte ahead SetMetaField(HEADER_FADE.ToString(), Utils.Latin1Encoding.GetString(fade), readTagParams.ReadAllMetaFrames, ZONE_HEADER); } else { fadeVal = TrackUtils.ExtractTrackNumber(Utils.Latin1Encoding.GetString(fade)); songVal = TrackUtils.ExtractTrackNumber(Utils.Latin1Encoding.GetString(song)); SetMetaField(HEADER_FADE.ToString(), Utils.Latin1Encoding.GetString(fade), readTagParams.ReadAllMetaFrames, ZONE_HEADER); } SetMetaField(HEADER_DUMPDATE.ToString(), Utils.Latin1Encoding.GetString(date), readTagParams.ReadAllMetaFrames, ZONE_HEADER); SetMetaField(HEADER_SONGLENGTH.ToString(), Utils.Latin1Encoding.GetString(song), readTagParams.ReadAllMetaFrames, ZONE_HEADER); // if fadeval > 0 alone, the fade is applied on the default 3:00 duration without extending it if (songVal > 0) { duration = Math.Round((double)fadeVal) + songVal; } SetMetaField(HEADER_ARTIST.ToString(), Utils.Latin1Encoding.GetString(source.ReadBytes(32)).Replace("\0", "").Trim(), readTagParams.ReadAllMetaFrames, ZONE_HEADER); header.Size += source.BaseStream.Position - initialPosition; if (readTagParams.PrepareForWriting) { structureHelper.AddZone(initialPosition, (int)(source.BaseStream.Position - initialPosition), ZONE_HEADER); } }
protected void readExistingTagsOnFile(AudioDataManager theFile, int nbPictures = 2) { Assert.IsTrue(theFile.ReadFromFile(true, true)); Assert.IsNotNull(theFile.getMeta(tagType)); IMetaDataIO meta = theFile.getMeta(tagType); Assert.IsTrue(meta.Exists); // Supported fields if (testData.Title != null) { Assert.AreEqual(testData.Title, meta.Title); } if (testData.Album != null) { Assert.AreEqual(testData.Album, meta.Album); } if (testData.Artist != null) { Assert.AreEqual(testData.Artist, meta.Artist); } if (testData.AlbumArtist != null) { Assert.AreEqual(testData.AlbumArtist, meta.AlbumArtist); } if (testData.Comment != null) { Assert.AreEqual(testData.Comment, meta.Comment); } if (testData.RecordingYear != null) { Assert.AreEqual(testData.RecordingYear, meta.Year); } //if (testData.RecordingDate != null) Assert.AreEqual(testData.RecordingDate, meta.); if (testData.Genre != null) { Assert.AreEqual(testData.Genre, meta.Genre); } if (testData.Rating != null) { if (Utils.IsNumeric(testData.Rating)) { float f = float.Parse(testData.Rating); Assert.AreEqual((f / 5.0).ToString(), meta.Popularity.ToString()); } else if (0 == testData.Rating.Length) { Assert.AreEqual("0", meta.Popularity.ToString()); } else { Assert.AreEqual(testData.Rating, meta.Popularity.ToString()); } } if (testData.TrackNumber != null) { Assert.AreEqual(TrackUtils.ExtractTrackNumber(testData.TrackNumber).ToString(), meta.Track.ToString()); } if (testData.Composer != null) { Assert.AreEqual(testData.Composer, meta.Composer); } if (testData.DiscNumber != null) { Assert.AreEqual(TrackUtils.ExtractTrackNumber(testData.DiscNumber).ToString(), meta.Disc.ToString()); } if (testData.Conductor != null) { Assert.AreEqual(testData.Conductor, meta.Conductor); } if (testData.Publisher != null) { Assert.AreEqual(testData.Publisher, meta.Publisher); } if (testData.Copyright != null) { Assert.AreEqual(testData.Copyright, meta.Copyright); } if (testData.GeneralDescription != null) { Assert.AreEqual(testData.GeneralDescription, meta.GeneralDescription); } // Unsupported field if (testData.AdditionalFields != null && testData.AdditionalFields.Count > 0) { foreach (MetaFieldInfo field in testData.AdditionalFields) { Assert.IsTrue(meta.AdditionalFields.Keys.Contains(field.NativeFieldCode)); Assert.AreEqual(field.Value, meta.AdditionalFields[field.NativeFieldCode]); } } // Pictures if (testData.Pictures != null && testData.Pictures.Count > 0) { Assert.AreEqual(nbPictures, meta.EmbeddedPictures.Count); byte nbFound = 0; foreach (PictureInfo pic in meta.EmbeddedPictures) { foreach (PictureInfo testPicInfo in testData.Pictures) { if (pic.NativePicCode.Equals(testPicInfo.NativePicCode) || (pic.NativePicCodeStr != null && pic.NativePicCodeStr.Equals(testPicInfo.NativePicCodeStr)) ) { nbFound++; pic.ComputePicHash(); Assert.AreEqual(testPicInfo.PictureHash, pic.PictureHash); } } } Assert.AreEqual(testData.Pictures.Count, nbFound); } }