PageRenderTime 48ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/Mp3TagPropertySheet/Mp3Tag/ID3v2.cs

http://tsanie-shellextension.googlecode.com/
C# | 309 lines | 286 code | 17 blank | 6 comment | 46 complexity | 13bba2aa50f90c07a0feaf73e44fc8fc MD5 | raw file
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Text;
  4. using System.IO;
  5. using Tsanie.ShellExtension;
  6. namespace Tsanie.Mp3Tag {
  7. public class ID3v2 : TagBase {
  8. private byte[] _b;
  9. private Encoding _encoding;
  10. private FileStream _fs;
  11. private List<Frame> _frames;
  12. private long _dataOffset;
  13. public int TagCount { get { return _frames.Count; } }
  14. public Frame this[int index] { get { return _frames[index]; } }
  15. public Frame this[string ID] {
  16. get {
  17. for (int i = 0; i < _frames.Count; i++) {
  18. Frame f = _frames[i];
  19. if (f.FrameID == ID)
  20. return f;
  21. }
  22. return null;
  23. }
  24. }
  25. private ID3v2() {
  26. _b = new byte[4];
  27. _dataOffset = 0;
  28. _frames = new List<Frame>();
  29. _encoding = null;
  30. }
  31. public ID3v2(FileStream fs)
  32. : this() {
  33. _fs = fs;
  34. Read();
  35. }
  36. public ID3v2(string filename)
  37. : this() {
  38. _fs = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
  39. }
  40. public byte[] PictureData {
  41. get {
  42. Frame pic = this["APIC"];
  43. if (pic != null)
  44. return pic.Data;
  45. return null;
  46. }
  47. set {
  48. Frame pic = this["APIC"];
  49. if (pic == null)
  50. pic = this.Add(new Frame() { FrameID = "APIC" });
  51. pic.Data = value;
  52. }
  53. }
  54. public Encoding Encoding { set { _encoding = value; } }
  55. #region TagBase Members
  56. public override string Title {
  57. get { return this["TIT2"].DataString(_encoding); }
  58. set {
  59. Frame frame = this["TIT2"];
  60. if (frame == null)
  61. frame = this.Add(new Frame() { FrameID = "TIT2" });
  62. frame.Data = value.ToTagBytes();
  63. }
  64. }
  65. public override string Artist {
  66. get { return this["TPE1"].DataString(_encoding); }
  67. set {
  68. Frame frame = this["TPE1"];
  69. if (frame == null)
  70. frame = this.Add(new Frame() { FrameID = "TPE1" });
  71. frame.Data = value.ToTagBytes();
  72. }
  73. }
  74. public override string Album {
  75. get { return this["TALB"].DataString(_encoding); }
  76. set {
  77. Frame frame = this["TALB"];
  78. if (frame == null)
  79. frame = this.Add(new Frame() { FrameID = "TALB" });
  80. frame.Data = value.ToTagBytes();
  81. }
  82. }
  83. public override string Year {
  84. get { return this["TYER"].DataString(); }
  85. set {
  86. Frame frame = this["TYER"];
  87. if (frame == null)
  88. frame = this.Add(new Frame() { FrameID = "TYER" });
  89. frame.Data = value.ToTagBytes(Encoding.ASCII);
  90. }
  91. }
  92. public override string Comments {
  93. get { return this["COMM"].DataString(_encoding); }
  94. set {
  95. Frame frame = this["COMM"];
  96. if (frame == null)
  97. frame = this.Add(new Frame() { FrameID = "COMM" });
  98. frame.Data = value.ToTagBytes();
  99. }
  100. }
  101. public override string Track {
  102. get { return this["TRCK"].DataString(); }
  103. set {
  104. Frame frame = this["TRCK"];
  105. if (frame == null)
  106. frame = this.Add(new Frame() { FrameID = "TRCK" });
  107. frame.Data = value.ToTagBytes(Encoding.ASCII);
  108. }
  109. }
  110. public override string Genre {
  111. get { return TagUtil.GetGenre(this["TCON"].DataString()); }
  112. set {
  113. foreach (KeyValuePair<int, string> kv in Definition.Genres) {
  114. if (kv.Value == value) {
  115. Frame frame = this["TCON"];
  116. if (frame == null)
  117. frame = this.Add(new Frame() { FrameID = "TCON" });
  118. frame.Data = ("(" + kv.Key + ")").ToTagBytes(Encoding.ASCII);
  119. }
  120. }
  121. }
  122. }
  123. public override void Read() {
  124. _fs.Seek(5, SeekOrigin.Begin);
  125. _fs.Read(_b, 1); // Flags
  126. bool ext = ((_b[0] & 64) == 64);
  127. _fs.Read(_b, 4); // ID3v2 Size
  128. _dataOffset = _b.ToTagInt();
  129. if (ext) // ? Extended Header
  130. _fs.Seek(10, SeekOrigin.Current);
  131. int count = 0;
  132. while (count < _dataOffset) {
  133. // ??Tag
  134. Frame f = Frame.ReadFrame(_fs);
  135. if (f == null)
  136. break;
  137. _frames.Add(f);
  138. count += f.FrameSize + 10;
  139. }
  140. }
  141. public override void Write() {
  142. if (_fs == null)
  143. return;
  144. _fs.Close();
  145. int frameSize = 0;
  146. foreach (Frame f in _frames) {
  147. frameSize += 10 + f.FrameSize;
  148. }
  149. if (frameSize <= _dataOffset) {
  150. // ID3v2 ????????????????
  151. _fs = new FileStream(_fs.Name, FileMode.Open, FileAccess.Write, FileShare.Read);
  152. WriteTag(_dataOffset, _fs);
  153. byte[] padding = new byte[_dataOffset - frameSize];
  154. _fs.Write(padding, 0, padding.Length);
  155. #if TRACE
  156. Common.OutputDebugString("Write(void):: overwrite tags.");
  157. #endif
  158. } else {
  159. // ??????
  160. _fs = new FileStream(_fs.Name, FileMode.Open, FileAccess.Read, FileShare.Read);
  161. _fs.Seek(_dataOffset, SeekOrigin.Begin);
  162. byte[] buffer = new byte[1024];
  163. int count;
  164. MemoryStream bufferStream = new MemoryStream();
  165. while ((count = _fs.Read(buffer, 0, buffer.Length)) > 0) {
  166. bufferStream.Write(buffer, 0, count);
  167. }
  168. _fs.Close();
  169. // Padding
  170. int padding = 0x400 - ((frameSize + 10) % 0x400);
  171. _dataOffset = frameSize + padding;
  172. // start
  173. _fs = new FileStream(_fs.Name, FileMode.Create, FileAccess.Write, FileShare.Read);
  174. WriteTag(_dataOffset, _fs);
  175. _fs.Write(new byte[padding], 0, padding);
  176. // ????
  177. _fs.Write(bufferStream.ToArray(), 0, (int)bufferStream.Length);
  178. #if TRACE
  179. Common.OutputDebugString("Write(void):: rewrite whole file.");
  180. #endif
  181. }
  182. _fs.Flush();
  183. _fs.Close();
  184. }
  185. private void WriteTag(long frameSize, FileStream fs) {
  186. fs.Write(new byte[] { 0x49, 0x44, 0x33, 0x03, 0, 0 }, 0, 6); // Header flag
  187. fs.Write(((int)frameSize).ToTagIntBytes(), 0, 4); // Total Frames size
  188. WriteFrames();
  189. }
  190. private void WriteFrames() {
  191. foreach (Frame f in _frames) {
  192. _fs.Write(f.FrameIDBytes, 0, 4);
  193. _fs.Write(f.FrameSizeBytes, 0, 4);
  194. _fs.Write(f.FlagsBytes, 0, 2);
  195. _fs.Write(f.Data, 0, f.Data.Length);
  196. }
  197. }
  198. #endregion
  199. public Frame Add(Frame f) {
  200. _frames.Add(f);
  201. return f;
  202. }
  203. public void Remove(string ID) {
  204. for (int i = 0; i < _frames.Count; i++) {
  205. if (_frames[i].FrameID == ID) {
  206. _frames.RemoveAt(i);
  207. return;
  208. }
  209. }
  210. }
  211. public void RemoveAt(int index) {
  212. _frames.RemoveAt(index);
  213. }
  214. }
  215. public class Frame {
  216. public static byte[] buffer = new byte[4];
  217. public static Frame ReadFrame(FileStream stream) {
  218. stream.Read(buffer, 4);
  219. if (buffer[0] == 0 || buffer[1] == 0 || buffer[2] == 0 || buffer[3] == 0) {
  220. return null;
  221. }
  222. Frame f = new Frame();
  223. f._FrameID = buffer.ToID();
  224. Array.Copy(buffer, 0, f._frameID, 0, 4);
  225. stream.Read(buffer, 4);
  226. f._FrameSize = buffer.ToInt();
  227. Array.Copy(buffer, 0, f._frameSize, 0, 4);
  228. stream.Read(buffer, 2);
  229. f._Flags = buffer.ToShort();
  230. Array.Copy(buffer, 0, f._flags, 0, 2);
  231. f._DataOffset = stream.Position;
  232. f._Data = new byte[f._FrameSize];
  233. stream.Read(f._Data, f._FrameSize);
  234. return f;
  235. }
  236. private string _FrameID;
  237. private int _FrameSize;
  238. private short _Flags;
  239. private long _DataOffset;
  240. internal byte[] _Data;
  241. private byte[] _frameID = new byte[4];
  242. private byte[] _frameSize = new byte[4];
  243. private byte[] _flags = new byte[2];
  244. public string FrameID {
  245. get { return this._FrameID; }
  246. set {
  247. this._FrameID = value;
  248. this._frameID = Encoding.ASCII.GetBytes(value);
  249. }
  250. }
  251. public int FrameSize {
  252. get { return this._FrameSize; }
  253. set {
  254. this._FrameSize = value;
  255. this._frameSize = value.ToIntBytes();
  256. }
  257. }
  258. public short Flags {
  259. get { return this._Flags; }
  260. set {
  261. this._Flags = value;
  262. this._flags = new byte[] { (byte)((value >> 8) & 0xff), (byte)(value & 0xff) };
  263. }
  264. }
  265. public long DataOffset {
  266. get { return this._DataOffset; }
  267. }
  268. public byte[] Data {
  269. get { return this._Data; }
  270. set {
  271. this._Data = value;
  272. this.FrameSize = value.Length;
  273. }
  274. }
  275. public byte[] FrameIDBytes { get { return this._frameID; } }
  276. public byte[] FrameSizeBytes { get { return this._frameSize; } }
  277. public byte[] FlagsBytes { get { return this._flags; } }
  278. public override string ToString() {
  279. return string.Format("{0} {1}: 0x{2:X8}", this.FrameID, this.FrameSize.ToString().PadLeft(8), this.DataOffset);
  280. }
  281. }
  282. static class FrameExtension {
  283. public static string DataString(this Frame frame) {
  284. return frame.DataString(null);
  285. }
  286. public static string DataString(this Frame frame, Encoding encoding) {
  287. if (frame == null)
  288. return null;
  289. return frame._Data.ToTagString(encoding);
  290. }
  291. }
  292. }