rtoss - Blame information for rev 26

Subversion Repositories:
Rev:
Rev Author Line No. Line
14 roytam 1 #include <windows.h>
2 #include <tchar.h>
3 #include "maplay.h"
4 #include "reader.h"
5 #include "mahelper.h"
6  
26 roytam 7 #ifndef _WIN32_WCE
8 #include "stdio.h"
9 #endif // _WIN32_WCE
10  
14 roytam 11 const int tabbitrate[3][3][16] =
12 {
13    {{0,32,64,96,128,160,192,224,256,288,320,352,384,416,448,},          //V1L1
14         {0,32,48,56, 64, 80, 96,112,128,160,192,224,256,320,384,},              //V1L2
15         {0,32,40,48, 56, 64, 80, 96,112,128,160,192,224,256,320,} },    //V1L3
16  
17    {{0,32,48,56,64,80,96,112,128,144,160,176,192,224,256,},                     //V2L1
18         {0,8,16,24,32,40,48,56,64,80,96,112,128,144,160,},                              //V2L2
19         {0,8,16,24,32,40,48,56,64,80,96,112,128,144,160,} },                    //V2L3
20  
21    {{0,32,48,56,64,80,96,112,128,144,160,176,192,224,256,},                     //V2.5L1
22         {0,8,16,24,32,40,48,56,64,80,96,112,128,144,160,},                              //V2.5L2
23         {0,8,16,24,32,40,48,56,64,80,96,112,128,144,160,} }                             //V2.5L3
24 };
25  
26 const int tabsamplingrate[3][4] =
27 {
28         {44100, 48000, 32000, 0},
29         {22050, 24000, 16000, 0},
30         {11025, 12000, 8000, 0}
31 };
32  
33 const LPTSTR genre_strings[] = {
34         _T("Blues"), _T("Classic Rock"), _T("Country"), _T("Dance"), _T("Disco"),
35         _T("Funk"), _T("Grunge"), _T("Hip-Hop"), _T("Jazz"), _T("Metal"),
36         _T("New Age"), _T("Oldies"), _T("Other"), _T("Pop"), _T("R&B"),
37         _T("Rap"), _T("Reggae"), _T("Rock"), _T("Techno"), _T("Industrial"),
38         _T("Alternative"), _T("Ska"), _T("Death Metal"), _T("Pranks"), _T("Soundtrack"),
39         _T("Euro-Techno"), _T("Ambient"), _T("Trip-Hop"), _T("Vocal"), _T("Jazz+Funk"),
40         _T("Fusion"), _T("Trance"), _T("Classical"), _T("Instrumental"), _T("Acid"),
41         _T("House"), _T("Game"), _T("Sound Clip"), _T("Gospel"), _T("Noise"),
42         _T("Alternative Rock"), _T("Bass"), _T("Soul"), _T("Punk"), _T("Space"),
43         _T("Meditative"), _T("Instrumental Pop"), _T("Instrumental Rock"), _T("Ethnic"), _T("Gothic"),
44         _T("Darkwave"), _T("Techno-Industrial"), _T("Electronic"), _T("Pop-Folk"), _T("Eurodance"),
45         _T("Dream"), _T("Southern Rock"), _T("Comedy"), _T("Cult"), _T("Gangsta"),
46         _T("Top 40"), _T("Christian Rap"), _T("Pop/Funk"), _T("Jungle"), _T("Native American"),
47         _T("Cabaret"), _T("New Wave"), _T("Psychadelic"), _T("Rave"), _T("Showtunes"),
48         _T("Trailer"), _T("Lo-Fi"), _T("Tribal"), _T("Acid Punk"), _T("Acid Jazz"),
49         _T("Polka"), _T("Retro"), _T("Musical"), _T("Rock & Roll"), _T("Hard Rock"),
50         _T("Folk"), _T("Folk-Rock"), _T("National Folk"), _T("Swing"), _T("Fast Fusion"),
51         _T("Bebob"), _T("Latin"), _T("Revival"), _T("Celtic"), _T("Bluegrass"),
52         _T("Avantgarde"), _T("Gothic Rock"), _T("Progressive Rock"), _T("Psychedelic Rock"), _T("Symphonic Rock"),
53         _T("Slow Rock"), _T("Big Band"), _T("Chorus"), _T("Easy Listening"), _T("Acoustic"),
54         _T("Humour"), _T("Speech"), _T("Chanson"), _T("Opera"), _T("Chamber Music"),
55         _T("Sonata"), _T("Symphony"), _T("Booty Bass"), _T("Primus"), _T("Porn Groove"),
56         _T("Satire"), _T("Slow Jam"), _T("Club"), _T("Tango"), _T("Samba"),
57         _T("Folklore"), _T("Ballad"), _T("Power Ballad"), _T("Rhythmic Soul"), _T("Freestyle"),
58         _T("Duet"), _T("Punk Rock"), _T("Drum Solo"), _T("Acapella"), _T("Euro-House"),
59         _T("Dance Hall"), _T("Goa"), _T("Drum & Bass"), _T("Club-House"), _T("Hardcore"),
60         _T("Terror"), _T("Indie"), _T("BritPop"), _T("Negerpunk"), _T("Polsk Punk"),
61         _T("Beat"), _T("Christian Gangsta Rap"), _T("Heavy Metal"), _T("Black Metal"), _T("Crossover"),
62         _T("Contemporary Christian"), _T("Christian Rock"), _T("Merengue"), _T("Salsa"), _T("Thrash Metal"),
63         _T("Anime"), _T("Jpop"), _T("Synthpop"), NULL
64 };
65  
66 BOOL IsValidFile(LPCTSTR pszFile)
67 {
68         BOOL fRet = FALSE;
69         CReader* pReader = new CReader();
70         if (!pReader->Open(pszFile))
71                 return FALSE;
72  
73         // scan first 4096 bytes
74         DWORD dwRead;
75         BYTE bBuff[4096];
76         if (pReader->Read(bBuff, sizeof(bBuff), &dwRead) && dwRead >= 4) {
77                 DWORD dwBuff = MAKELONG(MAKEWORD(bBuff[3], bBuff[2]), MAKEWORD(bBuff[1], bBuff[0]));
78                 if ((dwBuff & 0xFFFFFF00) == 0x49443300)
79                         fRet = TRUE; // ID3v2 = MP3
80                 else if (dwBuff == 0x52494646) {
81                         // RIFF
82                         if (dwRead >= 12) {
83                                 dwBuff = MAKELONG(MAKEWORD(bBuff[11], bBuff[10]), MAKEWORD(bBuff[9], bBuff[8]));
84                                 if (dwBuff == 0x524D5033) // RMP3
85                                         fRet = TRUE;
86                                 else if (dwBuff == 0x57415645) { // RIFF Wave
87                                         if (dwRead >= 16) {
88                                                 dwBuff = MAKELONG(MAKEWORD(bBuff[15], bBuff[14]), MAKEWORD(bBuff[13], bBuff[12]));
89                                                 if (dwBuff == 0x666D7420) { // fmt
90                                                         if (dwRead >= 21) {
91                                                                 dwBuff = MAKELONG(MAKEWORD(bBuff[20], bBuff[21]), 0);
92                                                                 if (dwBuff == 0x55 ||
93                                                                         dwBuff == 0x50) // format id
94                                                                         fRet = TRUE;
95                                                         }
96                                                 }
97                                         }
98                                 }
99                         }
100                 }
101                 else {
102                         DWORD cb = 0;
103                         while (cb < dwRead - 4) {
104                                 MPEG_AUDIO_INFO info1, info2;
105                                 if (ParseHeader(bBuff + cb, &info1)) {
106                                         if (cb + info1.nFrameSize + 4 < dwRead) {
107                                                 ParseHeader(bBuff + cb + info1.nFrameSize, &info2);
108                                                 if (info1.nVersion == info2.nVersion &&
109                                                         info1.nLayer == info2.nLayer &&
110                                                         info1.nSamplingRate == info2.nSamplingRate) {
111                                                                 fRet = TRUE;
112                                                                 break;
113                                                 }
114                                         }
115                                 }
116                                 cb++;
117                         }
118                 }
119         }
120         pReader->Close();
121         delete pReader;
122         return fRet;
123 }
124  
125 BOOL ParseHeader(DWORD dwHeader, MPEG_AUDIO_INFO* pinfo)
126 {
127         if (!CheckAudioHeader(dwHeader))
128                 return FALSE;
129  
130         int nPadding;
131         MPEG_AUDIO_INFO info;
132         info.nVersion = (dwHeader & 0x00100000) ? 2 - ((dwHeader & 0x00080000) >> 19) : 3;
133         info.nLayer = 4 - ((dwHeader & 0x00060000) >> 17);
134         info.nBitRate = tabbitrate[info.nVersion - 1][info.nLayer - 1][(dwHeader & 0x0000F000) >> 12];
135         info.nSamplingRate = tabsamplingrate[info.nVersion - 1][(dwHeader & 0x00000C00) >> 10];
136         nPadding = (dwHeader & 0x00000200) >> 9;
137         info.nChannels = (((dwHeader & 0x000000C0) >> 6) == 3) ? 1 : 2;
138         if (!info.nSamplingRate)
139                 return FALSE;
140  
141         if (!info.nBitRate)
142                 return FALSE;   // freeformat
143  
144         if (info.nLayer == 1) {
145                 info.nFrameSize = (12 * info.nBitRate * 1000 / info.nSamplingRate + nPadding) * 4;
146                 info.nSamplesPerFrame = 384;
147         }
148         else {
149                 if (info.nLayer >= 2 && info.nVersion >= 2) {
150                         // LSF
151                         info.nFrameSize = 72 * info.nBitRate * 1000 / info.nSamplingRate + nPadding;
152                         info.nSamplesPerFrame = 576;
153                 }
154                 else {
155                         info.nFrameSize = 144 * info.nBitRate * 1000 / info.nSamplingRate + nPadding;
156                         info.nSamplesPerFrame = 1152;
157                 }
158         }
159         *pinfo = info;
160         return TRUE;
161 }
162  
163 BOOL ParseHeader(LPBYTE pbHeader, MPEG_AUDIO_INFO* pinfo)
164 {
165         DWORD dwHeader = MAKELONG(MAKEWORD(pbHeader[3], pbHeader[2]),
166                                                                 MAKEWORD(pbHeader[1], pbHeader[0]));
167         return ParseHeader(dwHeader, pinfo);
168 }
169  
170 int GetFrameSize(DWORD dwHeader)
171 {
172         if (CheckAudioHeader(dwHeader))
173                 return 0;
174  
175         MPEG_AUDIO_INFO info;
176         if (!ParseHeader(dwHeader, &info))
177                 return 0;
178  
179         return info.nFrameSize;
180 }
181  
182 int GetFrameSize(LPBYTE pbHeader)
183 {
184         DWORD dwHeader = MAKELONG(MAKEWORD(pbHeader[3], pbHeader[2]),
185                                                                 MAKEWORD(pbHeader[1], pbHeader[0]));
186         return GetFrameSize(dwHeader);
187 }
188  
189 void ConvertFromTagStr(BYTE buff[30], LPTSTR pszBuff, int nLen)
190 {
191         char szBuff[31];
192         memset(szBuff, 0, sizeof(szBuff));
193         memcpy(szBuff, buff, sizeof(BYTE) * nLen);
194         for (int i = nLen - 1; szBuff[i] == ' '; i--)
195                 szBuff[i] = '\0';
196  
197 #ifdef _UNICODE
198         MultiByteToWideChar(CP_ACP, 0, (char*)szBuff, -1, pszBuff, 31);
199 #else
200         strcpy(pszBuff, szBuff);
201 #endif
202 }
203  
26 roytam 204 int UTF8toUTF16(char* pszSrc, WCHAR* pszDst, DWORD dwDstLen)
14 roytam 205 {
26 roytam 206         DWORD dwLen = 0;
207         while (*pszSrc) {
208                 if (++dwLen == dwDstLen)
209                         break;
210                 if ((*pszSrc & 0x80) == 0x0) {
211                         // 1 byte
212                         *pszDst++ = *pszSrc++;
213                 }
214                 else if ((*pszSrc & 0xE0) == 0xC0) {
215                         // 2 bytes
216                         *pszDst++ = (((WORD)*pszSrc & 0x1F) << 6) | ((WORD)*(pszSrc + 1) & 0x3F);
217                         pszSrc += 2;
218                 }
219                 else if ((*pszSrc & 0xE0) == 0xE0) {
220                         // 3 bytes
221                         *pszDst++ = (((WORD)*pszSrc & 0x0F) << 12) | (((WORD)*(pszSrc + 1) & 0x3F) << 6) | ((WORD)*(pszSrc + 2) & 0x3F);
222                         pszSrc += 3;
223                 }
224         }
14 roytam 225  
26 roytam 226         *pszDst = NULL;
227         return dwLen;
228 }
229  
230 BOOL CopyTagStringW(BYTE *buf, int buflen, LPWSTR str, int strlen)
231 {
232         int len, i;
233         BOOL ret = FALSE;
234         BYTE tmp;
235         LPBYTE ptr;
236         char* psz = NULL;
237  
238         if (buf[0] == 0) {
239                 // ANSI
240                 len = buflen - 1;
241                 psz = new char[len + 1];
242                 if (!psz)
243                         return FALSE;
244  
245                 memset(psz, 0, len + 1);
246                 memcpy(psz, (char*)&buf[1], len);
247  
248                 MultiByteToWideChar(CP_ACP, 0, psz, -1, str, strlen);
249                 str [strlen - 1] = NULL;
250                 ret = TRUE;
251         }
252         else if (buf[1] == 0xFF && buf[2] == 0xFE) {
253                 // UCS2LE with BOM
254                 len = buflen - 3;
255                 len = len < (strlen - 1) * sizeof(WCHAR) ? len : (strlen - 1) * sizeof(WCHAR);
256                 memcpy(str, &buf[3], len);
257                 str[len / 2] = NULL;
258                 ret = TRUE;
259         }
260         else if (buf[1] == 0xFE && buf[2] == 0xFF) {
261                 // UCS2BE with BOM
262                 len = buflen - 3;
263                 len = len < (strlen - 1) * sizeof(WCHAR) ? len : (strlen - 1) * sizeof(WCHAR);
264                 memcpy(str, &buf[3], len);
265                 str[len / 2] = NULL;
266  
267                 ptr = (LPBYTE)str;
268                 for (i = 0; i < len / 2; i++) {
269                         tmp = ptr[i * 2 + 1];
270                         ptr[i * 2] = ptr[i * 2 + 1];
271                         ptr[i * 2 + 1] = tmp;
272                 }
273                 ret = TRUE;
274         }
275         else if (buf[0] == 2) {
276                 // UCS2BE
277                 len = buflen - 1;
278                 len = len < (strlen - 1) * sizeof(WCHAR) ? len : (strlen - 1) * sizeof(WCHAR);
279                 memcpy(str, &buf[1], len);
280                 str[len / 2] = NULL;
281  
282                 ptr = (LPBYTE)str;
283                 for (i = 0; i < len / 2; i++) {
284                         tmp = ptr[i * 2 + 1];
285                         ptr[i * 2] = ptr[i * 2 + 1];
286                         ptr[i * 2 + 1] = tmp;
287                 }
288                 ret = TRUE;
289         }
290         else if (buf[0] == 3) {
291                 // UTF-8
292                 len = buflen - 1;
293                 psz = new char[len + 1];
294                 if (!psz)
295                         return FALSE;
296  
297                 memset(psz, 0, len + 1);
298                 memcpy(psz, (char*)&buf[1], len);
299                 UTF8toUTF16(psz, str, strlen);
300                 ret = TRUE;
301         }
302  
303         if (psz) delete [] psz;
304         return ret;
305 }
306  
307 BOOL CopyTagString(BYTE *buf, int buflen, LPTSTR str, int strlen)
308 {
309 #ifdef _UNICODE
310         return CopyTagStringW(buf, buflen, str, strlen);
311 #else
312         WCHAR szTemp[MAX_PLUGIN_TAG_STR];
313         if (!CopyTagStringW(buf, buflen, szTemp, MAX_PLUGIN_TAG_STR))
14 roytam 314                 return FALSE;
315  
26 roytam 316         WideCharToMultiByte(CP_ACP, 0, szTemp, -1, str, strlen, NULL, NULL);
317         str[strlen - 1] = NULL;
318         return TRUE;
319 #endif
320 }
14 roytam 321  
26 roytam 322 BOOL ParseGenre(LPTSTR src, LPTSTR str, int strlen)
323 {
324         LPTSTR psz;
325         int nGenre;
14 roytam 326  
26 roytam 327         if (src[0] == _T('(')) {
328                 psz = _tcschr(&src[1], _T(')'));
329                 if (psz) {
330                         *psz = NULL;
331                         nGenre = _tcstol(&src[1], 0, 10);
14 roytam 332  
26 roytam 333                         if (nGenre < sizeof(genre_strings) / sizeof(LPTSTR)) {
334                                 _tcsncpy(str, genre_strings[nGenre], strlen);
335                                 str[strlen - 1] = NULL;
336                                 return TRUE;
14 roytam 337                         }
26 roytam 338                 }
339         }
340  
341         _tcsncpy(str, src, strlen);
342         str[strlen - 1] = NULL;
343  
344         return TRUE;
345 }
14 roytam 346  
26 roytam 347 BOOL ParseFrameV20(BYTE *buf, int len, ID3TAGV1* pTag)
348 {
349         LPTSTR psz;
350         TCHAR szTemp[MAX_PLUGIN_TAG_STR];
351         LPBYTE data = buf + ID3TAG20_FRAME_LEN;
352         int datalen = len - ID3TAG20_FRAME_LEN;
353  
354         if (memcmp(buf, "TT2", 3) == 0) {
355                 return CopyTagString(data, datalen, pTag->szTrack, MAX_PLUGIN_TAG_STR);
356         }
357         else if (memcmp(buf, "TAL", 3) == 0) {
358                 return CopyTagString(data, datalen, pTag->szAlbum, MAX_PLUGIN_TAG_STR);
359         }
360         else if (memcmp(buf, "TP1", 3) == 0) {
361                 return CopyTagString(data, datalen, pTag->szArtist, MAX_PLUGIN_TAG_STR);
362         }
363         else if (memcmp(buf, "TCO", 3) == 0) {
364                 if (CopyTagString(data, datalen, szTemp, MAX_PLUGIN_TAG_STR)) {
365                         return ParseGenre(szTemp, pTag->szGenre, MAX_PLUGIN_TAG_STR);
14 roytam 366                 }
367         }
26 roytam 368         else if (memcmp(buf, "TRK", 3) == 0) {
369                 if (CopyTagString(data, datalen, szTemp, MAX_PLUGIN_TAG_STR)) {
370                         psz = _tcschr(szTemp, _T('/'));
371                         if (psz)
372                                 *psz = NULL;
373                         pTag->nTrackNum = _tcstol(szTemp, 0, 10);
374                         return TRUE;
375                 }
376         }
377         else if (memcmp(buf, "TYE", 3) == 0) {
378                 if (CopyTagString(data, datalen, szTemp, MAX_PLUGIN_TAG_STR)) {
379                         pTag->nYear = _tcstol(szTemp, 0, 10);
380                         return TRUE;
381                 }
382         }
383  
384         return FALSE;
14 roytam 385 }
386  
26 roytam 387 BOOL ParseFrameV23(BYTE *buf, int len, ID3TAGV1* pTag)
388 {
389         LPTSTR psz;
390         TCHAR szTemp[MAX_PLUGIN_TAG_STR];
391         LPBYTE data = buf + ID3TAG23_FRAME_LEN;
392         int datalen = len - ID3TAG23_FRAME_LEN;
393  
394         if (memcmp(buf, "TIT2", 4) == 0) {
395                 return CopyTagString(data, datalen, pTag->szTrack, MAX_PLUGIN_TAG_STR);
396         }
397         else if (memcmp(buf, "TALB", 4) == 0) {
398                 return CopyTagString(data, datalen, pTag->szAlbum, MAX_PLUGIN_TAG_STR);
399         }
400         else if (memcmp(buf, "TPE1", 4) == 0) {
401                 return CopyTagString(data, datalen, pTag->szArtist, MAX_PLUGIN_TAG_STR);
402         }
403         else if (memcmp(buf, "TCON", 4) == 0) {
404                 if (CopyTagString(data, datalen, szTemp, MAX_PLUGIN_TAG_STR)) {
405                         return ParseGenre(szTemp, pTag->szGenre, MAX_PLUGIN_TAG_STR);
406                 }
407         }
408         else if (memcmp(buf, "TRCK", 4) == 0) {
409                 if (CopyTagString(data, datalen, szTemp, MAX_PLUGIN_TAG_STR)) {
410                         psz = _tcschr(szTemp, _T('/'));
411                         if (psz)
412                                 *psz = NULL;
413                         pTag->nTrackNum = _tcstol(szTemp, 0, 10);
414                         return TRUE;
415                 }
416         }
417         else if (memcmp(buf, "TDRC", 4) == 0) {
418                 if (CopyTagString(data, datalen, szTemp, MAX_PLUGIN_TAG_STR)) {
419                         if (_tcslen(szTemp) > 4)
420                                 szTemp[4] = NULL;
421                         pTag->nYear = _tcstol(szTemp, 0, 10);
422                         return TRUE;
423                 }
424         }
425         else if (memcmp(buf, "TYER", 4) == 0) {
426                 if (CopyTagString(data, datalen, szTemp, MAX_PLUGIN_TAG_STR)) {
427                         pTag->nYear = _tcstol(szTemp, 0, 10);
428                         return TRUE;
429                 }
430         }
431  
432         return FALSE;
433 }
434  
435 BOOL ParseId3TagV20(LPBYTE buf, int buflen, ID3TAGV1* pTag)
436 {
437         int tagsize, framesize;
438  
439         if (buflen < ID3TAG_HEADER_LEN + ID3TAG20_FRAME_LEN)
440                 return FALSE;
441  
442         tagsize = (buf[6] << 21) | (buf[7] << 14) | (buf[8] << 7) | (buf[9] << 0);
443         if (buflen < tagsize + ID3TAG_HEADER_LEN)
444                 tagsize = buflen - ID3TAG_HEADER_LEN;
445  
446         buf += ID3TAG_HEADER_LEN;
447         while (tagsize > ID3TAG20_FRAME_LEN) {
448                 framesize = (buf[3] << 16 | buf[4] << 8 | buf[5] << 0);
449                 if (framesize == 0)
450                         break;
451  
452                 if (framesize > tagsize)
453                         break;
454  
455                 ParseFrameV20(buf, framesize + ID3TAG20_FRAME_LEN, pTag);
456                 tagsize -= framesize + ID3TAG20_FRAME_LEN;
457                 buf += framesize + ID3TAG20_FRAME_LEN;
458         }
459         return TRUE;
460 }
461  
462 BOOL ParseId3TagV23(LPBYTE buf, int buflen, ID3TAGV1* pTag)
463 {
464         int tagsize, framesize;
465  
466         if (buflen < ID3TAG_HEADER_LEN + ID3TAG23_FRAME_LEN)
467                 return FALSE;
468  
469         tagsize = (buf[6] << 21) | (buf[7] << 14) | (buf[8] << 7) | (buf[9] << 0);
470         if (buflen < tagsize + ID3TAG_HEADER_LEN)
471                 tagsize = buflen - ID3TAG_HEADER_LEN;
472  
473         buf += ID3TAG_HEADER_LEN;
474         while (tagsize > ID3TAG23_FRAME_LEN) {
475                 framesize = (buf[4] << 24 | buf[5] << 16 | buf[6] << 8 | buf[7] << 0) & 0x7FFFFFFF;
476                 if (framesize == 0)
477                         break;
478  
479                 if (framesize > tagsize)
480                         break;
481  
482                 ParseFrameV23(buf, framesize + ID3TAG23_FRAME_LEN, pTag);
483                 tagsize -= framesize + ID3TAG23_FRAME_LEN;
484                 buf += framesize + ID3TAG23_FRAME_LEN;
485         }
486         return TRUE;
487 }
488  
489 BOOL ParseId3TagV2(LPBYTE buf, int buflen, ID3TAGV1* pTag)
490 {
491         if (buflen < ID3TAG_HEADER_LEN)
492                 return FALSE;
493  
494         if (memcmp(buf, "ID3", 3) != 0)
495                 return FALSE;
496  
497         if (buf[3] > 4)
498                 return FALSE;
499  
500         else if (buf[3] < 3)
501                 return ParseId3TagV20(buf, buflen, pTag);
502         else
503                 return ParseId3TagV23(buf, buflen, pTag);
504 }
505  
506 BOOL GetId3TagV2(FILE* fp, ID3TAGV1* pTag)
507 {
508         BYTE header[10];
509         BYTE *buf = NULL;
510         BYTE *ptr = NULL;
511         BOOL ret = FALSE;
512         long curoffset = ftell(fp);
513         int tagsize;
514         fseek(fp, 0, SEEK_SET);
515         int version;
516  
517         if (fread(header, 1, ID3TAG_HEADER_LEN, fp) != ID3TAG_HEADER_LEN) {
518                 goto done;
519         }
520  
521         if (memcmp(header, "ID3", 3) != 0) {
522                 goto done;
523         }
524  
525         version = header[3];
526         if (version > 4)
527                 goto done;
528  
529         tagsize = (header[6] << 21) | (header[7] << 14) | (header[8] << 7) | (header[9] << 0);
530         buf = new BYTE[tagsize + ID3TAG_HEADER_LEN];
531         if (!buf) {
532                 goto done;
533         }
534         memcpy(buf, header, ID3TAG_HEADER_LEN);
535         if (fread(buf + ID3TAG_HEADER_LEN, 1, tagsize, fp) != tagsize) {
536                 goto done;
537         }
538  
539         ret = ParseId3TagV2(buf, tagsize + ID3TAG_HEADER_LEN, pTag);
540  
541 done:
542         if (buf) delete [] buf;
543         fseek(fp, curoffset, SEEK_SET);
544         return ret;
545 }
546  
547 BOOL GetId3TagV1(FILE* fp, ID3TAGV1* pTag)
548 {
549         char buff[5];
550         ID3_TAG_V1 id3tag;
551         BOOL bRet = FALSE;
552  
553         long curoffset = ftell(fp);
554         fseek(fp, -sizeof(ID3_TAG_V1), SEEK_END);
555  
556         if (!fread(&id3tag, sizeof(ID3_TAG_V1), 1, fp))
557                 goto done;
558  
559         if (id3tag.tag[0] != 'T' || id3tag.tag[1] != 'A' || id3tag.tag[2] != 'G')
560                 goto done;
561  
562         bRet = TRUE;
563         memset(buff, 0, sizeof(buff));
564         memcpy(buff, id3tag.year, sizeof(id3tag.year));
565         pTag->nYear = atoi(buff);
566  
567         ConvertFromTagStr(id3tag.albumName, pTag->szAlbum, 30);
568         ConvertFromTagStr(id3tag.artistName, pTag->szArtist, 30);
569         ConvertFromTagStr(id3tag.trackName, pTag->szTrack, 30);
570  
571         //ID3TAG v1.1
572         if (id3tag.comment[28] == NULL) {
573                 pTag->nTrackNum = id3tag.comment[29];
574                 ConvertFromTagStr(id3tag.comment, pTag->szComment, 28);
575         }
576         else
577                 ConvertFromTagStr(id3tag.comment, pTag->szComment, 30);
578  
579         if (id3tag.genre < 148)
580                 _tcscpy(pTag->szGenre, genre_strings[id3tag.genre]);
581         else
582                 memset(pTag->szGenre, 0, sizeof(pTag->szGenre));
583  
584 done:
585         fseek(fp, curoffset, SEEK_SET);
586         return bRet;
587 }
588  
589 BOOL GetId3Tag(LPCTSTR pszFile, ID3TAGV1* pTag)
590 {
591         BOOL bRet;
592         FILE* fp = _tfopen(pszFile, _T("rb"));
593         if (!fp)
594                 return FALSE;
595  
596         bRet = GetId3TagV2(fp, pTag);
597         if (!bRet)
598                 bRet = GetId3TagV1(fp, pTag);
599  
600         fclose(fp);
601         return bRet;
602 }
603  
14 roytam 604 BOOL SetId3Tag(LPCTSTR pszFile, ID3TAGV1* pTag)
605 {
606         return FALSE;
26 roytam 607 }