フレームIDの先頭が'0'..'9'、'A'..'Z'でない場合はフレームではないと判定していますがもしかしたら'A'..'Z'だけで判定して良いのかも知れません。
ただ仕様書にはフレームIDの先頭には数字は不可とかそういったことは書かれていないようなので判定条件に入れています。
F_ReadFrameでフレームを解析してみてそれがフレームではないと判断された(F_iFrameHeaderSize
= 0)らデータの途中であったとしてもそこでタグは終了しているものとします。
というのも最後のフレームの後に余分な空白データ(パディングと言います)があることもあり、タグのサイズにはその分も含まれるからです。
interface
uses
Windows;
type
TMyTagID3 =
class(TObject)
private
F_sFileName:
WideString;
F_iTagSize: DWORD;
//全部のタグのサイズ
F_sFrameID:
WideString;
//フレームID
F_iFrameHeaderSize: DWORD;
//フレームヘッダーのサイズ
F_iFrameSize: DWORD;
//フレームのサイズ
//Version
F_sVersion:
WideString;
F_iVer,
F_iMajor,
F_iRev: Byte;
//Tag
F_sTrack,
//TRCK トラックの番号/セット中の位置
F_sSeries,
//TIT1 内容の属するグループの説明
F_sTitle,
//TIT2 タイトル/曲名/内容の説明
F_sSubTitle,
//TIT3 サブタイトル/説明の追加情報
F_sAlbum,
//TALB アルバム/映画/ショーのタイトル
F_sAuthor,
//TPE1 主な演奏者/ソリスト
F_sBand,
//TPE2 バンド/オーケストラ/伴奏
F_sConductor,
//TPE3 指揮者/演奏者詳細情報
F_sComposer,
//TCOM 作曲者
F_sWriter,
//TEXT 作詞家/文書作成者
F_sTranslator,
//TPE4 翻訳者, リミックス, その他の修正
F_sPublisher,
//TPUB 出版社, レーベル
F_sGenre,
//TCON ジャンル
F_sLength,
//TLEN 長さ
F_sYear,
//TYER 年
F_sDate,
//TDAT 日付
F_sLylic,
//USLT 非同期 歌詞/文書のコピー
F_sOriginalAlbum,
//TOAL オリジナルのアルバム/映画/ショーのタイトル
F_sOriginalWriter,
//TOLY オリジナルの作詞家/文書作成者
F_sOriginalAuthor,
//TOPE オリジナルアーティスト/演奏者
F_sOriginalRelease,
//TORY オリジナルのリリース年
F_sComment:
WideString;
//COMM コメント/説明
function F_GetSyncsafeSize(pData: PAnsiChar; iCount: Byte): Longword;
function F_GetSize(pData: PAnsiChar; iCount: Byte): Longword;
procedure F_ReadHeader;
function F_GetText (pData: PAnsiChar; iCount: DWORD):
WideString;
function F_GetFullText(pData: PAnsiChar; iCount: DWORD):
WideString;
procedure F_ReadFrame(pData: PAnsiChar);
procedure F_SetFileName(sFileName:
WideString);
procedure F_Clear;
procedure F_ReadV1;
procedure F_ReadV2;
public
constructor Create(sFile:
WideString);
property FileName:
WideString read F_sFileName
write F_SetFileName;
property Version:
WideString read F_sVersion;
property Major: Byte
read F_iMajor;
property Ver: Byte
read F_iVer;
property Rev: Byte
read F_iRev;
property Track:
WideString read F_sTrack;
property Series:
WideString read F_sSeries;
property Title:
WideString read F_sTitle;
property SubTitle:
WideString read F_sSubTitle;
property Album:
WideString read F_sAlbum;
property Author:
WideString read F_sAuthor;
property Band:
WideString read F_sBand;
property Conductor:
WideString read F_sConductor;
property Composer:
WideString read F_sComposer;
property Writer:
WideString read F_sWriter;
property Translator:
WideString read F_sTranslator;
property Publisher:
WideString read F_sPublisher;
property Genre:
WideString read F_sGenre;
property Length:
WideString read F_sLength;
property Year:
WideString read F_sYear;
property Date:
WideString read F_sDate;
property Lylic:
WideString read F_sLylic;
property OriginalAlbum:
WideString read F_sOriginalAlbum;
property OriginalWriter:
WideString read F_sOriginalWriter;
property OriginalAuthor:
WideString read F_sOriginalAuthor;
property OriginalRelease:
WideString read F_sOriginalRelease;
property Comment:
WideString read F_sComment;
end;
//------------------------------------------------------------------------------
implementation
uses
SysUtils,
Forms;
//------------------------------------------------------------------------------
//汎用ルーチン
function gfniFileRead(
var pData: PAnsiChar; sFile:
WideString; iOffset, iByte: DWORD): DWORD;
//ファイルからiByteバイトを読み込んでpDataにセットし、読み込んだバイト数を返す
//iOffsetはファイルの先頭からの0ベースのオフセット
var
lh_Handle: THandle;
lr_Overlapped: TOverlapped;
li_Size: DWORD;
begin
lh_handle := CreateFileW(
PWideChar(sFile),
//ファイル名
GENERIC_READ,
//アクセスモード
FILE_SHARE_READ,
//共有モード
nil,
//セキュリティ
OPEN_EXISTING,
//作成方法
FILE_ATTRIBUTE_NORMAL,
//ファイル属性
0
//テンプレート
);
try
Result := 0;
if (lh_Handle <> 0)
then begin
FillChar(lr_Overlapped, SizeOf(TOverlapped), 0);
lr_Overlapped.Offset := iOffset;
li_Size := GetFileSize(lh_Handle,
nil);
//4GB以上のファイルはNG
if (iOffset < li_Size)
then begin
//オフセット分を引く
Dec(li_Size, iOffset);
if (iByte < li_Size)
then begin
li_Size := iByte;
end;
//呼び出し側でpDataのメモリーを開放をする必要あり
pData := AllocMem(li_Size + 2);
//WideString(pData)としても問題ないように
ReadFile(lh_Handle, pData^, li_Size, Result,
@lr_Overlapped);
end;
end;
finally
CloseHandle(lh_Handle);
end;
end;
function gfniFileEndRead(
var pData: PAnsiChar; sFile:
WideString; iByte: DWORD): DWORD;
//ファイルの後ろからiByteバイトを読み込んでpDataにセットし、読み込んだバイト数を返す
var
lh_Handle: THandle;
lr_Overlapped: TOverlapped;
li_Offset: DWORD;
begin
lh_handle := CreateFileW(
PWideChar(sFile),
//ファイル名
GENERIC_READ,
//アクセスモード
FILE_SHARE_READ,
//共有モード
nil,
//セキュリティ
OPEN_EXISTING,
//作成方法
FILE_ATTRIBUTE_NORMAL,
//ファイル属性
0);
//テンプレート
try
Result := 0;
if (lh_Handle <> 0)
then begin
FillChar(lr_Overlapped, SizeOf(TOverlapped), 0);
li_Offset := GetFileSize(lh_Handle, nil) - iByte;
//4GB以上のファイルはNG
if (li_Offset > 0)
then begin
lr_Overlapped.Offset := iOffset;
//呼び出し側でpDataのメモリーを開放をする必要あり
pData := AllocMem(iByte + 2);
//WideString(pData)としても問題ないように
ReadFile(lh_Handle, pData^, iByte, Result,
@lr_Overlapped);
end;
end;
finally
CloseHandle(lh_Handle);
end;
end;
function gfnsByteCopy(pStr: PAnsiChar; iIndex, iCount: DWORD): AnsiString;
//pStr[iIndex]からiCount個の文字列をコピーして返す
var
i: DWORD;
begin
SetLength(Result, iCount);
for i := 1
to iCount
do begin
Result[i] := pStr[iIndex + i -1];
end;
end;
type
TMyCharCode = (cdShift_JIS, cdUnicodeLE, cdUnicodeBE, cdUTF_16LE,
cdUTF_16BE, cdUTF_8, cdUTF_8N);
function gfnsWStrBCopy(pStr: PAnsiChar; iIndex, iCount: DWORD; cdCode: TMyCharCode):
WideString;
//pStr[iIndex]からiCountバイトの文字列をコピーしてWideStringにして返す
var
i: DWORD;
ls_Temp: AnsiString;
lp_Buff: PAnsiChar;
begin
if (pStr[iIndex] = #$EF)
and (pStr[iIndex +1] = #$BB)
and (pStr[iIndex +2] = #$BF)
then begin
//UTF-8 BOMあり
cdCode := cdUTF_8;
Inc(iIndex, 3);
Dec(iCount, 3);
end else
if (pStr[iIndex] = #$FF)
and (pStr[iIndex +1] = #$FE)
then begin
//UTF-16 BOMありのリトルエンディアン
cdCode := cdUnicodeLE;
Inc(iIndex, 2);
Dec(iCount, 2);
end else
if (pStr[iIndex] = #$FE)
and (pStr[iIndex +1] = #$FF)
then begin
//UTF-16 BOMありのビッグエンディアン
cdCode := cdUnicodeBE;
Inc(iIndex, 2);
Dec(iCount, 2);
end;
if (cdCode = cdUTF_16BE)
or (cdCode = cdUnicodeBE)
then begin
//UTF-16 ビッグエンディアン
lp_Buff := AllocMem(iCount + 2);
try
for i := 0
to iCount -1
do begin
if (i
mod 2 = 0)
then begin
lp_Buff[i] := pStr[iIndex + i +1];
lp_Buff[i + 1] := pStr[iIndex + i];
end;
end;
Result :=
WideString(PWideChar(lp_Buff));
finally
FreeMem(lp_Buff);
end;
end else begin
ls_Temp := gfnsByteCopy(pStr, iIndex, iCount);
if (cdCode = cdShift_JIS)
then begin
//Shift-JIS
Result := AnsiString(ls_Temp);
end else if (cdCode = cdUTF_8)
or (cdCode = cdUTF_8N)
then begin
//UTF-8
Result := UTF8Decode(ls_Temp);
end else if (cdCode = cdUnicodeLE)
or (cdCode = cdUTF_16LE)
then begin
//UTF-16 リトルエンディアン
Result :=
WideString(PWideChar(PChar(ls_Temp + #0#0)));
end;
end;
end;
//汎用ルーチン終わり
//------------------------------------------------------------------------------
const
lciTAG_HEADERSIZE = 10;
constructor TMyTagID3.Create(sFile:
WideString);
begin
inherited Create;
F_SetFileName(sFile);
end;
procedure TMyTagID3.F_SetFileName(sFileName:
WideString);
begin
F_sFileName := sFileName;
F_Clear;
//ID3v2としてヘッダーを読んでみる
F_ReadHeader;
if (F_iVer = 2)
then begin
//ID3v2
F_iVer := 2;
F_sVersion := WideFormat('%d.%d.%d', [F_iVer, F_iMajor, F_iRev]);
F_ReadV2;
end else begin
//ID3v2ではないのでID3v1として読んでみる
F_ReadV1;
if (F_iVer = 1)
then begin
//ID3v1だった
F_sVersion := WideFormat('%d.%d', [F_iVer, F_iMajor]);
end;
end;
end;
procedure TMyTagID3.
F_Clear;
//変数のクリア
begin
F_iTagSize := 0;
//タグ全体のサイズ
F_sFrameID := '';
//フレームID
F_iFrameHeaderSize := 0;
//フレームヘッダーのサイズ
F_iFrameSize := 0;
//フレームのサイズ
F_sVersion := '';
F_iVer := 0;
F_iMajor := 0;
F_iRev := 0;
F_sTrack := '';
//TRCK トラックの番号/セット中の位置
F_sSeries := '';
//TIT1 内容の属するグループの説明
F_sTitle := '';
//TIT2 タイトル/曲名/内容の説明
F_sSubTitle := '';
//TIT3 サブタイトル/説明の追加情報
F_sAlbum := '';
//TALB アルバム/映画/ショーのタイトル
F_sAuthor := '';
//TPE1 主な演奏者/ソリスト
F_sBand := '';
//TPE2 バンド/オーケストラ/伴奏
F_sConductor := '';
//TPE3 指揮者/演奏者詳細情報
F_sComposer := '';
//TCOM 作曲者
F_sWriter := '';
//TEXT 作詞家/文書作成者
F_sTranslator := '';
//TPE4 翻訳者, リミックス, その他の修正
F_sPublisher := '';
//TPUB 出版社, レーベル
F_sGenre := '';
//TCON ジャンル
F_sLength := '';
//TLEN 長さ
F_sYear := '';
//TYER 年
F_sDate := '';
//TDAT 日付
F_sLylic := '';
//USLT 非同期 歌詞/文書のコピー
F_sOriginalAlbum := '';
//TOAL オリジナルのアルバム/映画/ショーのタイトル
F_sOriginalWriter := '';
//TOLY オリジナルの作詞家/文書作成者
F_sOriginalAuthor := '';
//TOPE オリジナルアーティスト/演奏者
F_sOriginalRelease := '';
//TORY オリジナルのリリース年
F_sComment := '';
//COMM コメント
end;
function lfniPower(iBase, iExponent: WORD): Longword;
//累乗を返す。
var
i: Integer;
begin
if (iExponent = 0)
then begin
Result := 1;
end else begin
Result := iBase;
for i := 1
to iExponent - 1
do begin
Result := Result * iBase;
end;
end;
end;
function TMyTagID3.F_GetSyncsafeSize(pData: PAnsiChar; iCount: Byte): Longword;
{同期信号である %11111111 111xxxxx と同じパターンになるのを防ぐために最上位ビット
が常に0であるような表現の数値として返す。
%11111111 は16進ならxFF、10進なら255。
%01111111 は16進ならx7F、10進なら127。
通常1バイトは255(xFF)が最大値となるが上記の場合は127(x7F)が最大値であり128(x80)に
なると桁あがりする。
よってx100は通常なら256だが上記のような場合は128となる。
x10000は通常なら65536(256*256)だが16384(128*128)となる。
}
var
i: Integer;
begin
Result := 0;
for i := 0
to iCount -1
do begin
Inc(Result, Ord(pData[iCount -1 - i]) * lfniPower($80, i));
end;
{
↑は
Result :=
Ord(pData[0]) * $200000 + //128 * 128 * 128
Ord(pData[1]) * $4000 + //128 * 128
Ord(pData[2]) * $80 + //128
Ord(pData[3]);
というようなことを汎用的にやっている
}
end;
function TMyTagID3.F_GetSize(pData: PAnsiChar; iCount: Byte): Longword;
//↑と違い通常の数値として返す。
var
i: Integer;
begin
Result := 0;
for i := 0
to iCount -1
do begin
Inc(Result, Ord(pData[iCount -1 - i]) * lfniPower($100, i));
end;
end;
procedure TMyTagID3.F_ReadHeader;
var
lp_Buff: PAnsiChar;
li_Size: DWORD;
begin
li_Size :=
gfniFileRead(lp_Buff, F_sFileName, 0, lciTAG_HEADERSIZE);
//10バイト固定
try
if (li_Size = lciTAG_HEADERSIZE)
then begin
if (lp_Buff[0] = 'I')
and (lp_Buff[1] = 'D')
and (lp_Buff[2] = '3')
then begin
F_iVer := 2;
//最初の3バイトが'ID3' ID3v2
F_iMajor := Ord(lp_Buff[3]);
F_iRev := Ord(lp_Buff[4]);
F_iTagSize :=
F_GetSyncsafeSize(@lp_Buff[6], 4);
//サイズは4バイト
//このサイズにはヘッダー自身の10バイトは含まない
end;
end;
finally
FreeMem(lp_Buff);
end;
end;
procedure TMyTagID3.F_ReadFrame(pData: PAnsiChar);
begin
F_iFrameHeaderSize := 0;
//フレームIDが正しくない場合はフレームヘッダーのサイズは0のまま
if (pData[0]
in ['0'..'9', 'A'..'Z'])
then begin
if (F_iMajor = 2)
then begin
//Ver2.2
F_sFrameID :=
gfnsByteCopy(pData, 0, 3);
F_iFrameHeaderSize := 3 + 3;
//ID、サイズとも3バイトでフレームのヘッダーサイズは6バイト
F_iFrameSize :=
F_GetSize(@pData[3], 3);
//サイズは3バイトのフレームIDの次の3バイトでSyncsafeではない
end else if (F_iMajor >= 3)
then begin
//Ver2.3以上
//ID、サイズとも4バイト、2バイトのフラグでフレームのヘッダーサイズは10バイト
F_iFrameHeaderSize := 4 + 4 + 2;
F_sFrameID :=
gfnsByteCopy(pData, 0, 4);
if (F_iMajor = 3)
then begin
//Ver2.3
F_iFrameSize :=
F_GetSize(@pData[4], 4);
//サイズは4バイトのフレームIDの次の4バイトでSyncsafeではない
end else begin
//Ver2.4以上
F_iFrameSize :=
F_GetSyncsafeSize(@pData[4], 4);
//サイズは4バイトのフレームIDの次の4バイトでSyncsafe
end;
end;
end;
end;
function TMyTagID3.F_GetText(pData: PAnsiChar; iCount: DWORD):
WideString;
//改行を含まないテキストを返す
var
li_Index, li_Enc: DWORD;
begin
li_Enc := Ord(pData[0]);
li_Index := 1;
//1は文字エンコードを飛ばす
Dec(iCount);
//文字エンコード(1Byte)分を減らす
if (li_Enc = $0)
then begin
Result :=
gfnsByteCopy(pData, li_Index, iCount);
end else if (li_Enc = $1)
then begin
//BOMありのUTF-16
//とりあえずリトルエンディアンを指定しているが関数内でBOMを自動判定している
Result :=
gfnsWStrBCopy(pData, li_Index, iCount, cdUnicodeLE);
end else if (li_Enc = $2)
then begin
//BOMなしのビッグエンディアン
Result :=
gfnsWStrBCopy(pData, li_Index, iCount, cdUTF_16BE);
end else if (li_Enc = $3)
then begin
//UTF-8
Result := UTF8Decode(
gfnsByteCopy(pData, li_Index, iCount));
end else begin
Result := '';
end;
end;
function TMyTagID3.F_GetFullText(pData: PAnsiChar; iCount: DWORD):
WideString;
//USLT,COMMなどの改行を含むテキストを返す
var
i, li_Enc, li_Index: DWORD;
begin
li_Enc := Ord(pData[0]);
li_Index := (1 + 3);
//文字エンコード(1Byte)と言語コード(3Byte)を読み飛ばす
Dec(iCount, (1 + 3));
//文字エンコード(1Byte)と言語コード(3Byte)を減らす
if (li_Enc = $0)
//ISO-8859-1
or (li_Enc = $3)
//UTF-8
then begin
if (iCount > 0)
then begin
//Content decriptorを読み飛ばす
for i := 0
to iCount -1
do begin
if (pData[li_Index + i] = #0)
then begin
Dec(iCount, (i + 1));
Inc(li_Index, (i + 1));
Break;
end;
end;
Result :=
gfnsByteCopy(pData, li_Index, iCount);
if (li_Enc = $3)
then begin
//UTF-8
Result := UTF8Decode(Result);
end;
end else begin
Result := '';
end;
end else begin
//Unicode
//Content decriptorを読み飛ばす
for i := 0
to iCount -1
do begin //iCountは文字数ではなくバイト数
if (i
mod 2 = 1)
//Unicodeなので2バイトごとの処理
and (pData[li_Index + (i -1)] = #0)
//終了文字
and (pData[li_Index + i] = #0)
//2つで終了
then begin
Dec(iCount, (i + 1));
Inc(li_Index, (i + 1));
Break;
end;
end;
if (iCount > 0)
then begin
if (li_Enc = $1)
then begin
//BOMありのUTF-16
Result :=
gfnsWStrBCopy(pData, li_Index, iCount, cdUnicodeLE);
end else begin
//BOMなしのビッグエンディアン
Result :=
gfnsWStrBCopy(pData, li_Index, iCount, cdUTF_16BE);
end;
end else begin
Result := '';
end;
end;
end;
procedure TMyTagID3.
F_ReadV2;
var
lp_Buff: PAnsiChar;
li_Size, li_Offset: DWORD;
ls_Text:
WideString;
begin
if (F_iTagSize > 0)
then begin
li_Offset := 0;
li_Size :=
gfniFileRead(lp_Buff, F_sFileName, lciTAG_HEADERSIZE, F_iTag);
//10バイト目から読み込む
try
if (li_Size = F_iTagSize)
then begin
repeat
F_ReadFrame(@lp_Buff[li_Offset]);
Inc(li_Offset, F_iFrameHeaderSize);
if (F_iFrameSize > 0)
then begin
if (F_sFrameID = 'COMM')
or (F_sFrameID = 'COM')
then begin
//コメント
F_sComment :=
F_GetFullText(@lp_Buff[li_Offset], F_iFrameSize);
end else if (F_sFrameID = 'USLT')
or (F_sFrameID = 'ULT')
then begin
//歌詞
F_sLylic :=
F_GetFullText(@lp_Buff[li_Offset], F_iFrameSize);
end else if (F_sFrameID[1] = 'T')
then begin
//改行無しのテキスト
ls_Text :=
F_GetText(@lp_Buff[li_Offset], F_iFrameSize);
if (F_sFrameID = 'TRCK')
or (F_sFrameID = 'TRK')
then begin
//トラックの番号/セット中の位置
F_sTrack := ls_Text;
end else if (F_sFrameID = 'TIT1')
or (F_sFrameID = 'TT1')
then begin
//内容の属するグループの説明
F_sSeries := ls_Text;
end else if (F_sFrameID = 'TIT2')
or (F_sFrameID = 'TT2')
then begin
//タイトル/曲名/内容の説明
F_sTitle := ls_Text;
end else if (F_sFrameID = 'TIT3')
or (F_sFrameID = 'TT3')
then begin
//サブタイトル/説明の追加情報
F_sSubTitle := ls_Text;
end else if (F_sFrameID = 'TALB')
or (F_sFrameID = 'TAL')
then begin
//アルバム/映画/ショーのタイトル
F_sAlbum := ls_Text;
end else if (F_sFrameID = 'TPE1')
or (F_sFrameID = 'TP1')
then begin
//主な演奏者/ソリスト
F_sAuthor := ls_Text;
end else if (F_sFrameID = 'TPE2')
or (F_sFrameID = 'TP2')
then begin
//バンド/オーケストラ/伴奏
F_sBand := ls_Text;
end else if (F_sFrameID = 'TPE3')
or (F_sFrameID = 'TP3')
then begin
//指揮者/演奏者詳細情報
F_sConductor := ls_Text;
end else if (F_sFrameID = 'TCOM')
or (F_sFrameID = 'TCM')
then begin
//作曲者
F_sComposer := ls_Text;
end else if (F_sFrameID = 'TEXT')
or (F_sFrameID = 'TXT')
then begin
//作詞家/文書作成者
F_sWriter := ls_Text;
end else if (F_sFrameID = 'TPE4')
or (F_sFrameID = 'TP4')
then begin
//翻訳者, リミックス, その他の修正
F_sTranslator := ls_Text;
end else if (F_sFrameID = 'TPUB')
or (F_sFrameID = 'TPB')
then begin
//出版社, レーベル
F_sPublisher := ls_Text;
end else if (F_sFrameID = 'TCON')
or (F_sFrameID = 'TCN')
then begin
//ジャンル
F_sGenre := ls_Text;
end else if (F_sFrameID = 'TLEN')
or (F_sFrameID = 'TLE')
then begin
//長さ
F_sLength := ls_Text;
end else if (F_sFrameID = 'TYER')
or (F_sFrameID = 'TYE')
then begin
//年
F_sYear := ls_Text;
end else if (F_sFrameID = 'TDAT')
or (F_sFrameID = 'TDA')
then begin
//日付
F_sDate := ls_Text;
end else if (F_sFrameID = 'TOAL')
or (F_sFrameID = 'TOT')
then begin
//オリジナルのアルバム/映画/ショーのタイトル
F_sOriginalAlbum := ls_Text;
end else if (F_sFrameID = 'TOLY')
or (F_sFrameID = 'TOL')
then begin
//オリジナルの作詞家/文書作成者
F_sOriginalWriter := ls_Text;
end else if (F_sFrameID = 'TOPE')
or (F_sFrameID = 'TOA')
then begin
//オリジナルアーティスト/演奏者
F_sOriginalAuthor := ls_Text;
end else if (F_sFrameID = 'TORY')
or (F_sFrameID = 'TOR')
then begin
//オリジナルのリリース年
F_sOriginalRelease := ls_Text;
end;
end;
//F_iFrameSizeにはフレームごのサイズが入っている。
//これをオフセットに足しこむことでオフセットが次のフレームの頭の位置になる
Inc(li_Offset, F_iFrameSize);
end;
Application.ProcessMessages;
until (li_Offset >= F_iTagSize)
or (F_iFrameHeaderSize = 0);
end;
finally
FreeMem(lp_Buff);
end;
end;
end;
procedure TMyTagID3.
F_ReadV1;
{2008-04-02:
ID3タグVer1を取得
http://ja.wikipedia.org/wiki/ID3タグ
}
var
lp_Buff: PAnsiChar;
li_Size: DWORD;
begin
li_Size :=
gfniFileEndRead(lp_Buff, F_sFileName, 128);
try
if (li_Size = 128)
then begin
if (lp_Buff[0] = 'T')
and (lp_Buff[1] = 'A')
and (lp_Buff[2] = 'G')
then begin
F_iVer := 1;
F_sTitle :=
gfnsByteCopy(lp_Buff, 3, 30);
//曲名
F_sAuthor := gfnsByteCopy(lp_Buff, 33,
30);
//アーティスト
F_sAlbum := gfnsByteCopy(lp_Buff,
63, 30);
//アルバム
F_sYear := gfnsByteCopy(lp_Buff,
93, 4);
//日付
F_sComment := gfnsByteCopy(lp_Buff, 97, 30);
//コメント
F_sGenre := IntToStr(Ord(lp_Buff[127]));
//ジャンル
if (lp_Buff[125] = #0)
and (lp_Buff[126] <> #0)
then begin
F_sTrack := IntToStr(Ord(lp_Buff[126]));
//トラック
F_iMajor := 1;
end;
end;
end;
finally
FreeMem(lp_Buff);
end;
end;