206 lines
6.3 KiB
C#
206 lines
6.3 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
|
|
namespace NLayer.Decoder
|
|
{
|
|
class ID3Frame : FrameBase
|
|
{
|
|
internal static ID3Frame TrySync(uint syncMark)
|
|
{
|
|
if ((syncMark & 0xFFFFFF00U) == 0x49443300)
|
|
{
|
|
return new ID3Frame { _version = 2 };
|
|
}
|
|
|
|
if ((syncMark & 0xFFFFFF00U) == 0x54414700)
|
|
{
|
|
if ((syncMark & 0xFF) == 0x2B)
|
|
{
|
|
return new ID3Frame { _version = 1 };
|
|
}
|
|
else
|
|
{
|
|
return new ID3Frame { _version = 0 };
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
int _version;
|
|
|
|
ID3Frame()
|
|
{
|
|
|
|
}
|
|
|
|
protected override int Validate()
|
|
{
|
|
switch (_version)
|
|
{
|
|
case 2:
|
|
// v2, yay!
|
|
var buf = new byte[7];
|
|
if (Read(3, buf) == 7)
|
|
{
|
|
byte flagsMask;
|
|
switch (buf[0])
|
|
{
|
|
case 2:
|
|
flagsMask = 0x3F;
|
|
break;
|
|
case 3:
|
|
flagsMask = 0x1F;
|
|
break;
|
|
case 4:
|
|
flagsMask = 0x0F;
|
|
break;
|
|
default:
|
|
return -1;
|
|
}
|
|
|
|
// ignore the flags (we don't need them for the validation)
|
|
|
|
// get the size (7 bits per byte [MSB cleared])
|
|
var size = (buf[3] << 21)
|
|
| (buf[4] << 14)
|
|
| (buf[5] << 7)
|
|
| (buf[6]);
|
|
|
|
// finally, check to make sure that all the right bits are cleared
|
|
if (!(((buf[2] & flagsMask) | (buf[3] & 0x80) | (buf[4] & 0x80) | (buf[5] & 0x80) | (buf[6] & 0x80)) != 0 || buf[1] == 0xFF))
|
|
{
|
|
return size + 10; // don't forget the sync, flag & size bytes!
|
|
}
|
|
}
|
|
break;
|
|
case 1:
|
|
return 227 + 128;
|
|
case 0:
|
|
return 128;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
internal override void Parse()
|
|
{
|
|
// assume we have to process it now or else... we can still read the whole frame, so no biggie
|
|
switch (_version)
|
|
{
|
|
case 2:
|
|
ParseV2();
|
|
break;
|
|
case 1:
|
|
ParseV1Enh();
|
|
break;
|
|
case 0:
|
|
ParseV1(3);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void ParseV1(int offset)
|
|
{
|
|
//var buffer = new byte[125];
|
|
//if (Read(offset, buffer) == 125)
|
|
//{
|
|
// // v1 tags use ASCII encoding... For now we'll use the built-in encoding, but for Win8 we'll have to build our own.
|
|
// var encoding = Encoding.ASCII;
|
|
//
|
|
// // title (30)
|
|
// Title = encoding.GetString(buffer, 0, 30);
|
|
//
|
|
// // artist (30)
|
|
// Artist = encoding.GetString(buffer, 30, 30);
|
|
//
|
|
// // album (30)
|
|
// Album = encoding.GetString(buffer, 60, 30);
|
|
//
|
|
// // year (4)
|
|
// Year = encoding.GetString(buffer, 90, 30);
|
|
//
|
|
// // comment (30)*
|
|
// Comment = encoding.GetString(buffer, 94, 30);
|
|
//
|
|
// if (buffer[122] == 0)
|
|
// {
|
|
// // track (1)*
|
|
// Track = (int)buffer[123];
|
|
// }
|
|
//
|
|
// // genre (1)
|
|
// // ignore for now
|
|
//
|
|
// // * if byte 29 of comment is 0, track is byte 30. Otherwise, track is unknown.
|
|
//}
|
|
}
|
|
|
|
void ParseV1Enh()
|
|
{
|
|
ParseV1(230);
|
|
|
|
//var buffer = new byte[223];
|
|
//if (Read(4, buffer) == 223)
|
|
//{
|
|
// // v1 tags use ASCII encoding... For now we'll use the built-in encoding, but for Win8 we'll have to build our own.
|
|
// var encoding = Encoding.ASCII;
|
|
//
|
|
// // title (60)
|
|
// Title += encoding.GetString(buffer, 0, 60);
|
|
//
|
|
// // artist (60)
|
|
// Artist += encoding.GetString(buffer, 60, 60);
|
|
//
|
|
// // album (60)
|
|
// Album += encoding.GetString(buffer, 120, 60);
|
|
//
|
|
// // speed (1)
|
|
// //var speed = buffer[180];
|
|
//
|
|
// // genre (30)
|
|
// Genre = encoding.GetString(buffer, 181, 30);
|
|
//
|
|
// // start-time (6)
|
|
// // 211
|
|
//
|
|
// // end-time (6)
|
|
// // 217
|
|
//}
|
|
}
|
|
|
|
void ParseV2()
|
|
{
|
|
// v2 is much more complicated than v1... don't worry about it for now
|
|
// look for any merged frames, as well
|
|
}
|
|
|
|
internal int Version
|
|
{
|
|
get
|
|
{
|
|
if (_version == 0) return 1;
|
|
return _version;
|
|
}
|
|
}
|
|
|
|
//internal string Title { get; private set; }
|
|
//internal string Artist { get; private set; }
|
|
//internal string Album { get; private set; }
|
|
//internal string Year { get; private set; }
|
|
//internal string Comment { get; private set; }
|
|
//internal int Track { get; private set; }
|
|
//internal string Genre { get; private set; }
|
|
// speed
|
|
//public TimeSpan StartTime { get; private set; }
|
|
//public TimeSpan EndTime { get; private set; }
|
|
|
|
internal void Merge(ID3Frame newFrame)
|
|
{
|
|
// just save off the frame for parsing later
|
|
}
|
|
}
|
|
}
|