Not correct reading ID3v2
-
Hello, in my program, I want a reading of the ID3 of the Gate. He wrote a few classes for this (not yet written), but according to the results, even the writing is not quite correct. I didn't write part of the code myself, but I found it online, and I don't understand it, so if anyone knows, please explain it.
Classes that currently have:
- ID3TagReader is the main class that determines which version of the tags are in the file.
- ID3v1 - Reads ID3v1 of the tags if they are recorded in the file.
- ID3v2 - Read the ID3v2 of the tags if they are recorded in the file.
- MainHeader reads heading ID3v2 thega.
- FrameHeader reads headlines.
- FrameData - read the tag in the freime.
Please comment on the code(s) below, the efficiency(s) in relation to other other such programmes, the reading process is onerous to the PK, and the reading algorithm itself, and explain the commentaries of the code line.
ID3TagReader:
public class ID3TagReader { private FileStream fs; private ID3v1 ID3v1; private ID3v2 ID3v2; private string album; private BitmapImage albumArt; private string artist; private string title;
public ID3TagReader(string path) { fs = new FileStream(path, FileMode.Open, FileAccess.Read); //Непосредственно с этим файлстримом работают все остальные классы.
//Думаю далее все понятно.
ID3v1 = new ID3v1(ref fs);
ID3v2 = new ID3v2(ref fs);if (ID3v2.HasTag) { album = ID3v2.Album; albumArt = ID3v2.AlbumArt; artist = ID3v2.Artist; title = ID3v2.Title; } else if (ID3v1.HasTag) { album = ID3v1.Album; albumArt = null; artist = ID3v1.Artist; title = ID3v1.Title; } else { album = "Error"; albumArt = null; artist = "Error"; title = "Error"; } ID3v1 = null; ID3v2 = null; fs.Close(); } public string Album { get { return album; } } public BitmapImage AlbumArt { get { return albumArt; } } public string Artist { get { return artist; } } public string Title { get { return title; } }
}
ID3v1:
public class ID3v1 // С чтением ID3v1 у меня никаких проблем не возникло, соответственно вопросов тут нет.
{
private byte[] tags = new byte[128];public ID3v1(ref FileStream fs) { fs.Seek(-128, SeekOrigin.End); fs.Read(tags, 0, 128); } public bool HasTag { get { if (new ASCIIEncoding().GetString(tags).Substring(0, 3).Trim().Equals("TAG")) { return true; } else { tags = null; return false; } } } public string Album { get { return new ASCIIEncoding().GetString(tags).Substring(63, 30).Trim(); } } public string Artist { get { return new ASCIIEncoding().GetString(tags).Substring(33, 30).Trim(); } } public string Title { get { return new ASCIIEncoding().GetString(tags).Substring(3, 30).Trim(); } }
}
ID3v2:
public class ID3v2
{
private string album;
private BitmapImage albumArt;
private string artist;
private string title;private MainHeader header; private FrameHeader frameHeader; private FrameData frameData; private int size; private int position; public ID3v2(ref FileStream fs) { header = new MainHeader(ref fs); size = header.Size; position = 10; if (header.Marker.Equals("ID3")) { while (size > 0) { frameHeader = new FrameHeader(ref fs, position); frameData = new FrameData(ref fs, (position + 10), frameHeader.FrameSize); position = frameHeader.FrameSize + 10; switch (header.MajorVersion)
// Тут ещё не реализована
//логика конвертации массивов байт в текстовые значения и изображения,
//но поверхностно я понимаю как это сделать.
{
case 3:
{
break;
}
case 4:
{
break;
}
case 2:
{
throw new System.NotSupportedException("ID3v2.2 is not supported yet.");
}
default:
{
throw new System.NotSupportedException("This version of ID3v2 is not supported yet.");
}
}size = size - position; //position имеет такое же значение
//как и размер фрейма, не корректность работы заключается в том, что размер
//всего тега "size" является числом с 5-ю, а то и 6-ю знаками, а размер
//фрейма состоит, зачастую, из двух знаков, но при этом цикл повторяется
//лишь 2-3 раза.
}
}
}public bool HasTag { get { if (header.Marker.Equals("ID3")) { return true; } else { return false; } } } public string Album { get { return album; } } public BitmapImage AlbumArt { get { return albumArt; } } public string Artist { get { return artist; } } public string Title { get { return title; } }
}
MainHeader:
public class MainHeader
{
private byte[] header = new byte[10];public MainHeader(ref FileStream fs) { fs.Seek(0, SeekOrigin.Begin); fs.Read(header, 0, 10); } public string Marker { get { return Encoding.Default.GetString(header).Substring(0, 3).Trim(); } } public int MajorVersion { get { return header[3]; } } public int MinorVersion { get { return header[4]; } } // Далее флаги, этот код я нашел в сети, поэтому прошу объяснить его по подробнее. public bool Unsynchronisation { get { return ((header[5] & 0x80) == 0x80); } } public bool ExtendedHeader { get { return ((header[5] & 0x40) == 0x40); } } public bool ExperimentalIndicator { get { return ((header[5] & 0x20) == 0x20); } } public bool FooterPresent { get { return ((header[5] & 0x10) == 0x10); } } // Так же не очень понял что это за Sync-safe integer, которым является размер всех тегов, и как происходит конвертация байтовых значений в него. public int Size { get { return (header[9] & 0x7f) | (header[8] & 0x7f) << 7 | (header[7] & 0x7f) << 14 | (header[6] & 0x7f) << 21; } }
}
FrameHeader:
public class FrameHeader // Тут те же вопросы, что и по поводу MainHeader
{
private byte[] frameHeader = new byte[10];public FrameHeader(ref FileStream fs, int position) { fs.Seek(position, SeekOrigin.Begin); fs.Read(frameHeader, 0, 10); } public string FrameID { get { return Encoding.Default.GetString(frameHeader).Substring(0, 4).Trim(); } } public int FrameSize { get { return (frameHeader[7] & 0x7f) | (frameHeader[6] & 0x7f) << 7 | (frameHeader[5] & 0x7f) << 14 | (frameHeader[4] & 0x7f) << 21; } } public bool TagAlterPreservation { get { return ((frameHeader[8] & 0x80) == 0x80); } } public bool FileAlterPreservation { get { return ((frameHeader[8] & 0x40) == 0x40); } } public bool ReadOnly { get { return ((frameHeader[8] & 0x20) == 0x20); } } public bool GroupingIdentity { get { return ((frameHeader[9] & 0x20) == 0x20); } } public bool Compression { get { return ((frameHeader[9] & 0x80) == 0x80); } } public bool Encryption { get { return ((frameHeader[9] & 0x40) == 0x40); } } public bool Unsynchronisation { get { return ((frameHeader[9] & 0x01) == 0x01); } } public bool DataLengthIndicator { get { return ((frameHeader[9] & 0x03) == 0x03); } }
}
FrameData:
public class FrameData // Тут всё должно быть ясно.
{
private byte[] data;public FrameData(ref FileStream fs, int position, int size) { data = new byte[size]; fs.Seek(position, SeekOrigin.Begin); //Так как этот класс работает в цикле, позиция для чтения очередного тега будет обновляться. fs.Read(data, 0, size); } public byte[] Data { get { return data; } }
}
It's the whole code that's available for now.
So, I look forward to your amendments, comments and answers.
-
About the flags. Every battle is in charge of a certain meaning. Like a flag. ExperimentalIndicator Main title:
return ((header[5] & 0x20) == 0x20);
This flag is the third battle, and we need to get its meaning. To this end, the operation is full and (operator) of flags with a mosquito 0x20, that is, 00100000. If this flag is 1, the operation will result in 0x20; if 0, then 0x00.
Next, on synchsafe integer.
return (header[9] & 0x7f) | (header[8] & 0x7f) << 7 | (header[7] & 0x7f) << 14 | (header[6] & 0x7f) << 21;
The first battle of each of these numbers is always set at 0, so it does not make sense. The remaining seven battles remain known. They need to be blinded in a single number without ruptures. To this end, we're throwing away an insignificant battle by operation.
byte & 0x7f
and make a field trip to the left by 0/7/14/21while (size > 0) { //... size = size - position; }
Of course you have a mistake here. Must be something like:
while (size > position) { //... position += frameSize // где frameSize - размер текущего фрейма }
It's just, in your case, a step on the condition not on the size of the frimet, but on the size of the current that has already been read out.