我用 C# 编写了一个 ID3-Tag-Reader,它工作得很好,除了音频文件包含一个GEOB-Frame。阅读它的标题就像在每个其他框架中一样,所以我会得到正确的大小(因为我在每个其他框架中都这样做)。假设我得到Frames Body的大小为7725 Bytes。遍历我的数组显示,下一个 Frame 位于位置24497。那么我做错了什么?
public abstract class ID3v2Frame
{
/// <summary>
/// Gets or sets the frame identifier.
/// </summary>
/// <value>The frame identifier.</value>
public FrameIdentifier FrameIdentifier { get; set; }
/// <summary>
/// The Header of the Frame
/// </summary>
/// <value>The header.</value>
protected FrameHeader FrameHeader { get; set; }
/// <summary>
/// The Frame's Body which contains the values
/// </summary>
/// <value>The frame body.</value>
protected FrameBody FrameBody { get; set; }
/// <summary>
/// The size of Header added with the size of Body
/// </summary>
/// <value>The size of the frame.</value>
protected int FrameSize { get { return FrameHeader.HeaderSize + FrameHeader.BodySize; } }
public ID3v2Frame(){
}
public ID3v2Frame (ID3v2 version, FrameIdentifier identifier, String content)
{
this.FrameIdentifier = identifier;
FrameHeader = FrameHeader.CreateHeader(identifier.GetIDByVersion(version), content.Length);
FrameBody = FrameBody.CreateBody (content);
}
public ID3v2Frame (byte[] allBytes, FrameIdentifier identifier)
{
this.FrameIdentifier = identifier;
FrameHeader = new FrameHeader (allBytes);
byte[] bytesBody = new byte[allBytes.Length - FrameHeader.HeaderSize];
Array.Copy (allBytes, ID3v2Header.HeaderSize, bytesBody, 0, bytesBody.Length);
FrameBody = new FrameBody (bytesBody, FrameHeader.BodySize);
}
public virtual void SetValue (String value)
{
FrameBody.Content = value;
}
public virtual String GetValue ()
{
return FrameBody.Content;
}
public override string ToString ()
{
return FrameHeader + " - " + FrameBody;
}
public virtual byte[] GetAsByte ()
{
byte[] output = new byte[0];
FrameHeader.BodySize = FrameBody.GetContentLength ();
ArrayMerger.MergeArrays (ref output, FrameHeader.GetAsByteArray (), FrameBody.GetAsByteArray ());
return output;
}
public virtual int GetFrameSize ()
{
return FrameHeader.HeaderSize + FrameHeader.BodySize;
}
public virtual bool IsAvailableInVersion (ID3v2 version)
{
if (version is ID3v2_2 && this.FrameIdentifier.FrameID2_2 != "") {
return true;
} else if (version is ID3v2_3 && this.FrameIdentifier.FrameID2_3 != "") {
return true;
} else if (version is ID3v2_4 && this.FrameIdentifier.FrameID2_4 != "") {
return true;
} else {
return false;
}
}
/*
public static ID3v2Frame createFrame(String identifier){
ID3v2Frame frame = new ID3v2Frame (identifier);
frame.FrameHeader = FrameHeader.CreateHeader (identifier, 0);
frame.FrameBody = FrameBody.CreateBody ();
return frame;
} */
}
public class FrameHeader {
/// <summary>
/// Gets or sets the frame ID.
/// </summary>
/// <value>The frame ID.</value>
public String FrameID { get; set; }
/// <summary>
/// The frame ID.
/// </summary>
private byte[] frameID = new byte[4];
/// <summary>
/// The Size of the Frame's Body
/// </summary>
/// <value>The size of the body.</value>
public Int32 BodySize { get; set; }
/// <summary>
/// The size of the body.
/// </summary>
private byte[] bodySize = new byte[4];
/// <summary>
/// The flags: 0abc0000 0h00kmnp
/// </summary>
private byte[] flags = new byte[2];
/// <summary>
/// The size of the header.
/// </summary>
public const int HeaderSize = 10;
/// <summary>
/// a - Tag alter preservation
///
/// This flag tells the tag parser what to do with this frame if it is
/// unknown and the tag is altered in any way. This applies to all
/// kinds of alterations, including adding more padding and reordering
/// the frames.
///
/// 0 Frame should be preserved.
/// 1 Frame should be discarded.
/// </summary>
/// <value><c>true</c> if tag alter preservation; otherwise, <c>false</c>.</value>
public bool TagAlterPreservation { get; set; }
/// <summary>
/// b - File alter preservation
///
/// This flag tells the tag parser what to do with this frame if it is
/// unknown and the file, excluding the tag, is altered. This does not
/// apply when the audio is completely replaced with other audio data.
///
/// 0 Frame should be preserved.
/// 1 Frame should be discarded.
/// </summary>
/// <value><c>true</c> if file alter preservation; otherwise, <c>false</c>.</value>
public bool FileAlterPreservation { get; set; }
/// <summary>
/// c - Read only
///
/// This flag, if set, tells the software that the contents of this
/// frame are intended to be read only. Changing the contents might
/// break something, e.g. a signature. If the contents are changed,
/// without knowledge of why the frame was flagged read only and
/// without taking the proper means to compensate, e.g. recalculating
/// the signature, the bit MUST be cleared.
/// </summary>
/// <value><c>true</c> if tag alter preservation; otherwise, <c>false</c>.</value>
public bool ReadOnly { get; set; }
/// <summary>
/// h - Grouping identity
///
/// This flag indicates whether or not this frame belongs in a group
/// with other frames. If set, a group identifier byte is added to the
/// frame. Every frame with the same group identifier belongs to the
/// same group.
///
/// 0 Frame does not contain group information
/// 1 Frame contains group information
/// </summary>
/// <value><c>true</c> if grouping identity; otherwise, <c>false</c>.</value>
public bool GroupingIdentity { get; set; }
/// <summary>
/// k - Compression
///
/// This flag indicates whether or not the frame is compressed.
/// A 'Data Length Indicator' byte MUST be included in the frame.
///
/// 0 Frame is not compressed.
/// 1 Frame is compressed using zlib [zlib] deflate method.
/// If set, this requires the 'Data Length Indicator' bit
/// to be set as well.
/// </summary>
/// <value><c>true</c> if compression; otherwise, <c>false</c>.</value>
public bool Compression { get; set; }
/// <summary>
/// m - Encryption
///
/// This flag indicates whether or not the frame is encrypted. If set,
/// one byte indicating with which method it was encrypted will be
/// added to the frame. See description of the ENCR frame for more
/// information about encryption method registration. Encryption
/// should be done after compression. Whether or not setting this flag
/// requires the presence of a 'Data Length Indicator' depends on the
/// specific algorithm used.
///
/// 0 Frame is not encrypted.
/// 1 Frame is encrypted.
/// </summary>
/// <value><c>true</c> if encryption; otherwise, <c>false</c>.</value>
public bool Encryption { get; set; }
/// <summary>
/// n - Unsynchronisation
///
/// This flag indicates whether or not unsynchronisation was applied
/// to this frame. See section 6 for details on unsynchronisation.
/// If this flag is set all data from the end of this header to the
/// end of this frame has been unsynchronised. Although desirable, the
/// presence of a 'Data Length Indicator' is not made mandatory by
/// unsynchronisation.
///
/// 0 Frame has not been unsynchronised.
/// 1 Frame has been unsyrchronised.
/// </summary>
/// <value><c>true</c> if encryption; otherwise, <c>false</c>.</value>
public bool Unsynchronisation { get; set; }
/// <summary>
/// p - Data length indicator
///
/// This flag indicates that a data length indicator has been added to
/// the frame. The data length indicator is the value one would write
/// as the 'Frame length' if all of the frame format flags were
/// zeroed, represented as a 32 bit synchsafe integer.
///
/// 0 There is no Data Length Indicator.
/// 1 A data length Indicator has been added to the frame.
/// </summary>
/// <value><c>true</c> if data length indicator; otherwise, <c>false</c>.</value>
public bool DataLengthIndicator { get; set; }
public FrameHeader(){
}
public FrameHeader (byte[] bytes) {
this.Load (bytes);
}
public void Load (byte[] bytes) {
using (MemoryStream fs = new MemoryStream (bytes, true)) {
// Frame ID
fs.Read (frameID, 0, frameID.Length);
FrameID = Encoding.UTF8.GetString (frameID, 0, frameID.Length);
// Bodysize
fs.Read (bodySize, 0, bodySize.Length);
int testBodySize = BitConverter.ToInt32 (bodySize, 0);
BodySize = SynchsafeToInt (bodySize);
// Flags
fs.Read (flags, 0, flags.Length);
TagAlterPreservation = GetBit (flags [0], 1);
FileAlterPreservation = GetBit (flags [0], 2);
ReadOnly = GetBit (flags [0], 3);
GroupingIdentity = GetBit (flags [1], 1);
Compression = GetBit (flags [1], 4);
Encryption = GetBit (flags [1], 5);
Unsynchronisation = GetBit (flags [1], 6);
DataLengthIndicator = GetBit (flags [1], 7);
}
}
public int SynchsafeToInt(byte[] synchsafe)
{
if (BitConverter.IsLittleEndian)
Array.Reverse (synchsafe);
return BitConverter.ToInt32 (synchsafe, 0);
}
public byte[] SynchsafeToByteArray(int synchsafe){
byte[] theBytes = BitConverter.GetBytes (synchsafe);
if (BitConverter.IsLittleEndian)
Array.Reverse (theBytes);
return theBytes;
}
private bool GetBit (byte b, int bitNumber) {
return (b & (1 << bitNumber)) != 0;
}
public override string ToString () {
return FrameID;
}
public byte[] GetAsByteArray () {
byte[] output = new byte[0];
ArrayMerger.MergeArrays (ref output, output, TextEncoder.EncodeString (FrameID, 0));
byte[] bodySizeArray = SynchsafeToByteArray (this.BodySize);
ArrayMerger.MergeArrays (ref output, output, bodySizeArray);
ArrayMerger.MergeArrays (ref output, output, flags);
return output;
}
public static FrameHeader CreateHeader(String frameID, Int32 bodysize){
FrameHeader header = new FrameHeader ();
header.FrameID = frameID;
header.BodySize = bodysize;
return header;
}
}
public class GeneralObjectFrameBody : FrameBody{
public String MIMEType { get; set; }
private byte[] mimeBytes = new byte[0];
public String Filename { get; set; }
public GeneralObjectFrameBody (String content) {
}
public GeneralObjectFrameBody (byte[] bytes, int length) {
int index = 0;
for (int i = 0; i < bytes.Length; i++){
if (bytes[i] == 65){
byte[] tempBytes = new byte[4] { bytes[i], bytes[i+1], bytes[i +2],bytes[i +3]};
String tempString = TextEncoder.DecodeByteArray (tempBytes, 0);
Logger.output (tempString + " found at " + i);
if (bytes[i + 1] == 80){
if (bytes [i + 2] == 73) {
if (bytes [i + 3] == 67) {
Logger.output ("Next Frame found at " + i);
}
}
}
}
}
}
}
请帮帮我