/Mp3TagPropertySheet/Mp3Tag/ID3v2.cs
C# | 309 lines | 286 code | 17 blank | 6 comment | 46 complexity | 13bba2aa50f90c07a0feaf73e44fc8fc MD5 | raw file
- using System;
- using System.Collections.Generic;
- using System.Text;
- using System.IO;
- using Tsanie.ShellExtension;
-
- namespace Tsanie.Mp3Tag {
- public class ID3v2 : TagBase {
- private byte[] _b;
- private Encoding _encoding;
- private FileStream _fs;
- private List<Frame> _frames;
- private long _dataOffset;
-
- public int TagCount { get { return _frames.Count; } }
- public Frame this[int index] { get { return _frames[index]; } }
- public Frame this[string ID] {
- get {
- for (int i = 0; i < _frames.Count; i++) {
- Frame f = _frames[i];
- if (f.FrameID == ID)
- return f;
- }
- return null;
- }
- }
-
- private ID3v2() {
- _b = new byte[4];
- _dataOffset = 0;
- _frames = new List<Frame>();
- _encoding = null;
- }
- public ID3v2(FileStream fs)
- : this() {
- _fs = fs;
- Read();
- }
- public ID3v2(string filename)
- : this() {
- _fs = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
- }
-
- public byte[] PictureData {
- get {
- Frame pic = this["APIC"];
- if (pic != null)
- return pic.Data;
- return null;
- }
- set {
- Frame pic = this["APIC"];
- if (pic == null)
- pic = this.Add(new Frame() { FrameID = "APIC" });
- pic.Data = value;
- }
- }
- public Encoding Encoding { set { _encoding = value; } }
-
- #region TagBase Members
-
- public override string Title {
- get { return this["TIT2"].DataString(_encoding); }
- set {
- Frame frame = this["TIT2"];
- if (frame == null)
- frame = this.Add(new Frame() { FrameID = "TIT2" });
- frame.Data = value.ToTagBytes();
- }
- }
- public override string Artist {
- get { return this["TPE1"].DataString(_encoding); }
- set {
- Frame frame = this["TPE1"];
- if (frame == null)
- frame = this.Add(new Frame() { FrameID = "TPE1" });
- frame.Data = value.ToTagBytes();
- }
- }
- public override string Album {
- get { return this["TALB"].DataString(_encoding); }
- set {
- Frame frame = this["TALB"];
- if (frame == null)
- frame = this.Add(new Frame() { FrameID = "TALB" });
- frame.Data = value.ToTagBytes();
- }
- }
- public override string Year {
- get { return this["TYER"].DataString(); }
- set {
- Frame frame = this["TYER"];
- if (frame == null)
- frame = this.Add(new Frame() { FrameID = "TYER" });
- frame.Data = value.ToTagBytes(Encoding.ASCII);
- }
- }
- public override string Comments {
- get { return this["COMM"].DataString(_encoding); }
- set {
- Frame frame = this["COMM"];
- if (frame == null)
- frame = this.Add(new Frame() { FrameID = "COMM" });
- frame.Data = value.ToTagBytes();
- }
- }
- public override string Track {
- get { return this["TRCK"].DataString(); }
- set {
- Frame frame = this["TRCK"];
- if (frame == null)
- frame = this.Add(new Frame() { FrameID = "TRCK" });
- frame.Data = value.ToTagBytes(Encoding.ASCII);
- }
- }
- public override string Genre {
- get { return TagUtil.GetGenre(this["TCON"].DataString()); }
- set {
- foreach (KeyValuePair<int, string> kv in Definition.Genres) {
- if (kv.Value == value) {
- Frame frame = this["TCON"];
- if (frame == null)
- frame = this.Add(new Frame() { FrameID = "TCON" });
- frame.Data = ("(" + kv.Key + ")").ToTagBytes(Encoding.ASCII);
- }
- }
- }
- }
-
- public override void Read() {
- _fs.Seek(5, SeekOrigin.Begin);
- _fs.Read(_b, 1); // Flags
- bool ext = ((_b[0] & 64) == 64);
- _fs.Read(_b, 4); // ID3v2 Size
- _dataOffset = _b.ToTagInt();
- if (ext) // ? Extended Header
- _fs.Seek(10, SeekOrigin.Current);
- int count = 0;
- while (count < _dataOffset) {
- // ??Tag
- Frame f = Frame.ReadFrame(_fs);
- if (f == null)
- break;
- _frames.Add(f);
- count += f.FrameSize + 10;
- }
- }
- public override void Write() {
- if (_fs == null)
- return;
- _fs.Close();
- int frameSize = 0;
- foreach (Frame f in _frames) {
- frameSize += 10 + f.FrameSize;
- }
- if (frameSize <= _dataOffset) {
- // ID3v2 ????????????????
- _fs = new FileStream(_fs.Name, FileMode.Open, FileAccess.Write, FileShare.Read);
- WriteTag(_dataOffset, _fs);
- byte[] padding = new byte[_dataOffset - frameSize];
- _fs.Write(padding, 0, padding.Length);
- #if TRACE
- Common.OutputDebugString("Write(void):: overwrite tags.");
- #endif
- } else {
- // ??????
- _fs = new FileStream(_fs.Name, FileMode.Open, FileAccess.Read, FileShare.Read);
- _fs.Seek(_dataOffset, SeekOrigin.Begin);
- byte[] buffer = new byte[1024];
- int count;
- MemoryStream bufferStream = new MemoryStream();
- while ((count = _fs.Read(buffer, 0, buffer.Length)) > 0) {
- bufferStream.Write(buffer, 0, count);
- }
- _fs.Close();
- // Padding
- int padding = 0x400 - ((frameSize + 10) % 0x400);
- _dataOffset = frameSize + padding;
- // start
- _fs = new FileStream(_fs.Name, FileMode.Create, FileAccess.Write, FileShare.Read);
- WriteTag(_dataOffset, _fs);
- _fs.Write(new byte[padding], 0, padding);
- // ????
- _fs.Write(bufferStream.ToArray(), 0, (int)bufferStream.Length);
- #if TRACE
- Common.OutputDebugString("Write(void):: rewrite whole file.");
- #endif
- }
- _fs.Flush();
- _fs.Close();
- }
-
- private void WriteTag(long frameSize, FileStream fs) {
- fs.Write(new byte[] { 0x49, 0x44, 0x33, 0x03, 0, 0 }, 0, 6); // Header flag
- fs.Write(((int)frameSize).ToTagIntBytes(), 0, 4); // Total Frames size
- WriteFrames();
- }
- private void WriteFrames() {
- foreach (Frame f in _frames) {
- _fs.Write(f.FrameIDBytes, 0, 4);
- _fs.Write(f.FrameSizeBytes, 0, 4);
- _fs.Write(f.FlagsBytes, 0, 2);
- _fs.Write(f.Data, 0, f.Data.Length);
- }
- }
-
- #endregion
-
- public Frame Add(Frame f) {
- _frames.Add(f);
- return f;
- }
-
- public void Remove(string ID) {
- for (int i = 0; i < _frames.Count; i++) {
- if (_frames[i].FrameID == ID) {
- _frames.RemoveAt(i);
- return;
- }
- }
- }
- public void RemoveAt(int index) {
- _frames.RemoveAt(index);
- }
- }
-
- public class Frame {
- public static byte[] buffer = new byte[4];
- public static Frame ReadFrame(FileStream stream) {
- stream.Read(buffer, 4);
- if (buffer[0] == 0 || buffer[1] == 0 || buffer[2] == 0 || buffer[3] == 0) {
- return null;
- }
- Frame f = new Frame();
- f._FrameID = buffer.ToID();
- Array.Copy(buffer, 0, f._frameID, 0, 4);
- stream.Read(buffer, 4);
- f._FrameSize = buffer.ToInt();
- Array.Copy(buffer, 0, f._frameSize, 0, 4);
- stream.Read(buffer, 2);
- f._Flags = buffer.ToShort();
- Array.Copy(buffer, 0, f._flags, 0, 2);
- f._DataOffset = stream.Position;
- f._Data = new byte[f._FrameSize];
- stream.Read(f._Data, f._FrameSize);
- return f;
- }
-
- private string _FrameID;
- private int _FrameSize;
- private short _Flags;
- private long _DataOffset;
- internal byte[] _Data;
- private byte[] _frameID = new byte[4];
- private byte[] _frameSize = new byte[4];
- private byte[] _flags = new byte[2];
-
- public string FrameID {
- get { return this._FrameID; }
- set {
- this._FrameID = value;
- this._frameID = Encoding.ASCII.GetBytes(value);
- }
- }
- public int FrameSize {
- get { return this._FrameSize; }
- set {
- this._FrameSize = value;
- this._frameSize = value.ToIntBytes();
- }
- }
- public short Flags {
- get { return this._Flags; }
- set {
- this._Flags = value;
- this._flags = new byte[] { (byte)((value >> 8) & 0xff), (byte)(value & 0xff) };
- }
- }
- public long DataOffset {
- get { return this._DataOffset; }
- }
- public byte[] Data {
- get { return this._Data; }
- set {
- this._Data = value;
- this.FrameSize = value.Length;
- }
- }
- public byte[] FrameIDBytes { get { return this._frameID; } }
- public byte[] FrameSizeBytes { get { return this._frameSize; } }
- public byte[] FlagsBytes { get { return this._flags; } }
-
- public override string ToString() {
- return string.Format("{0} {1}: 0x{2:X8}", this.FrameID, this.FrameSize.ToString().PadLeft(8), this.DataOffset);
- }
- }
-
- static class FrameExtension {
- public static string DataString(this Frame frame) {
- return frame.DataString(null);
- }
- public static string DataString(this Frame frame, Encoding encoding) {
- if (frame == null)
- return null;
- return frame._Data.ToTagString(encoding);
- }
- }
-
- }