1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
|
{APE tag}
{$IFDEF Interface}
function ReadAPEv2(buf:PAnsiChar;var Info:tSongInfo;count:integer=0):longint; overload;
function ReadAPEv2(f:THANDLE;var Info:tSongInfo):longint; overload;
{$ELSE}
const
APESign = 'APETAGEX';
type
pAPEHeader = ^tAPEHeader;
tAPEHeader = packed record
ID:array [0..7] of AnsiChar;
Version:dword;
TagSize:dword; //footer + all items
ItemCount:dword;
TagFlags:dword;
Reserved:array [0..7] of byte;
end;
procedure ReadAPEValue(const buf:PAnsiChar;var dst:pWideChar;ver:dword);
begin
if dst=nil then
if ver>1000 then
UTF8ToWide(buf,dst)
else
AnsiToWide(buf,dst);
end;
function ReadAPEv2(buf:PAnsiChar;var Info:tSongInfo;count:integer=0):longint;
var
APE:pAPEHeader;
len:integer;
ptr,key:PAnsiChar;
flag:dword;
cf:THANDLE;
buf0,buf1:array [0..MAX_PATH-1] of AnsiChar;
b:AnsiChar;
// extw:array [0..7] of WideChar;
begin
result:=0;
APE:=pointer(buf);
if APE.ID=APESign then
begin
inc(buf,SizeOf(tAPEHeader));
count:=APE.ItemCount;
end;
while count>0 do
begin
len :=pdword(buf)^; inc(buf,4);
flag:=pdword(buf)^; inc(buf,4);
key:=buf;
while buf^<>#0 do inc(buf); inc(buf);
ptr:=buf+len;
b:=ptr^;
ptr^:=#0;
if lstrcmpia(key,'TITLE' )=0 then ReadAPEValue(buf,Info.title ,APE.Version)
else if lstrcmpia(key,'ARTIST' )=0 then ReadAPEValue(buf,Info.artist ,APE.Version)
else if lstrcmpia(key,'ALBUM' )=0 then ReadAPEValue(buf,Info.album ,APE.Version)
else if lstrcmpia(key,'COMMENT')=0 then ReadAPEValue(buf,Info.comment,APE.Version)
else if lstrcmpia(key,'GENRE' )=0 then ReadAPEValue(buf,Info.genre ,APE.Version)
else if lstrcmpia(key,'YEAR' )=0 then ReadAPEValue(buf,Info.year ,APE.Version)
else if lstrcmpia(key,'TRACK' )=0 then if Info.track=0 then Info.track:=StrToInt(buf)
else if lstrcmpia(key,'LYRICS' )=0 then ReadAPEValue(buf,Info.lyric ,APE.Version)
//!! must preserve multipart lyric
else if (lstrcmpia(key,'Cover Art (Front)')=0) or
(lstrcmpia(key,'Cover Art (Back)' )=0) or
(lstrcmpia(key,'APIC' )=0) then
begin
if Info.cover=nil then
begin
while buf^<>#0 do inc(buf); inc(buf); // point to data now
flag:=GetImageType(pByte(buf));
if flag<>0 then
begin
{
FastAnsiToWideBuf(PAnsiChar(@flag),pWideChar(@extw));
Info.Cover:=SaveTemporaryW(buf,ptr-buf,PWideChar(@extw));
}
GetTempPathA(SizeOf(buf0),buf0);
GetTempFileNameA(buf0,'wat',GetCurrentTime,buf1);
ChangeExt(buf1,PAnsiChar(@flag));
cf:=ReWrite(PAnsiChar(@buf1));
BlockWrite(cf,buf^,ptr-buf);
CloseHandle(cf);
AnsiToWide(PAnsiChar(@buf1),Info.cover);
end;
end;
end;
ptr^:=b;
buf:=ptr;
dec(count);
end;
end;
function ReadAPEv2(f:THANDLE;var Info:tSongInfo):longint;
var
APE:tAPEHeader;
buf:PAnsiChar;
fpos:dword;
TagID:array [1..3] of AnsiChar;
begin
result:=0;
fpos:=FileSize(f);
Seek(f,fpos-SizeOf(TID3v1Tag));
BlockRead(f,TagID,3);
if TagID=TAG1Sign then
dec(fpos,SizeOf(TID3v1Tag));
Seek(f,fpos-SizeOf(APE));
BlockRead(f,APE,SizeOf(APE));
// footer must be copied as header
if APE.ID=APESign then
begin
if (APE.TagFlags and $20000000)=0 then //Footer
begin
Seek(f,fpos-APE.TagSize{-SizeOf(APE)});// without header but with footer
GetMem(buf,APE.TagSize);
BlockRead(f,buf^,APE.TagSize);
result:=ReadAPEv2(buf,Info,APE.ItemCount);
FreeMem(buf);
end;
end;
end;
{$ENDIF}
|