1 /* EasyTAG - tag editor for audio files
2  * Copyright (C) 2014 David King <amigadave@amigadave.com>
3  * Copyright (C) 2002 Artur Polaczynski (Ar't) <artii@o2.pl>
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License as published by the Free
7  * Software Foundation; either version 2 of the License, or (at your option)
8  * any later version.
9  *
10  * This program is distributed in the hope that it will be useful, but WITHOUT
11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
13  * more details.
14  *
15  * You should have received a copy of the GNU General Public License along with
16  * this program; if not, write to the Free Software Foundation, Inc., 51
17  * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18  */
19 
20 #include <string.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <stddef.h>
24 #include <stdarg.h>
25 #include <string.h>
26 #include <limits.h>
27 #include <assert.h>
28 #include "is_tag.h"
29 #include "../id3_tag.h"
30 
31 /*
32     PL: czy dany plik ma taga odpowiednio id3v1, id3v2 i ape ???
33     PL: nie zmienia pozycji w pliku !!!
34 */
35 
36 static unsigned long
is_tag_ape2long(unsigned char * p)37 is_tag_ape2long (unsigned char *p)
38 {
39 
40     return (((unsigned long) p[0] << 0)  |
41             ((unsigned long) p[1] << 8)  |
42             ((unsigned long) p[2] << 16) |
43             ((unsigned long) p[3] << 24) );
44 
45 }
46 
47 /**
48     return size of all id3v1 tags (some bugy tagers add this again and
49     again tag) 0 no tag at all
50 
51     \param fp File pointer
52     \return Return size of id3v1 tag (in bytes) 0 no tag at all
53 */
54 int
is_id3v1(FILE * fp)55 is_id3v1 (FILE * fp)
56 {
57     int n=0;
58     char buf[16];
59     size_t savedFilePosition;
60 
61     savedFilePosition = ftell (fp);
62     fseek (fp, 0, SEEK_END);
63     do {
64         n++;
65         memset (buf, 0, sizeof (buf));
66         fseek (fp, ((-ID3V1_TAG_SIZE) * n) - 3, SEEK_END);
67         if (fread (&buf, 1, sizeof (buf), fp) != sizeof (buf))
68         {
69             fseek (fp, savedFilePosition, SEEK_SET);
70             return 0;
71         }
72         if (memcmp (buf, "APETAGEX",8) == 0) /*APE.TAG.EX*/
73         break;
74     } while (memcmp (buf+3, "TAG", 3) == 0);
75 
76     fseek (fp, savedFilePosition, SEEK_SET);
77     return (n - 1) * ID3V1_TAG_SIZE;
78 }
79 
80 /**
81     return size of tag id3v2 on begining of file.
82     check for buggy tagers (2 or more tags)
83 
84     \param fp File pointer
85     \return Return size of id3v2 tag (in bytes)
86     (some bugy tagers add this again and again ) 0 no tag at all
87 */
88 int
is_id3v2(FILE * fp)89 is_id3v2 (FILE * fp)
90 {
91     char buf[16];
92     size_t savedFilePosition;
93     long id3v2size=0;
94 
95     savedFilePosition = ftell (fp);
96     fseek (fp, 0, SEEK_SET);
97     do {
98         memset (buf, 0, sizeof (buf));
99         fseek (fp, id3v2size, SEEK_SET);
100         if (fread (&buf, 1, sizeof (buf), fp) != sizeof (buf))
101         {
102             fseek (fp, savedFilePosition, SEEK_SET);
103             return 0;
104         }
105         if (memcmp (buf, "ID3", 3) != 0) {
106         break;
107         }
108         /* ID3v2 tag skipeer $49 44 33 yy yy xx zz zz zz zz [zz size + this 10 bytes] */
109         id3v2size += 10 + (((long) (buf[9])) | ((long) (buf[8]) << 7) |
110         ((long) (buf[7]) << 14) | ((long) (buf[6]) << 21));
111     } while(memcmp (buf, "ID3", 3) == 0);
112 
113     fseek (fp, savedFilePosition, SEEK_SET);
114     return (int) id3v2size;
115 }
116 
117 
118 /**
119     return 0 or 1000 or 2000 this is version of ape tag 0 no tag
120 
121     \param fp File pointer
122     \return Version of ape tag if any, else 0
123 */
124 int
is_ape_ver(FILE * fp)125 is_ape_ver (FILE * fp)
126 {
127     char unsigned buf[32];
128     size_t savedFilePosition;
129 
130     savedFilePosition = ftell (fp);
131     memset (buf, 0, sizeof (buf));
132 
133     fseek (fp, (is_id3v1 (fp) ? -32 - ID3V1_TAG_SIZE : -32), SEEK_END);
134     if (fread (&buf, 1, sizeof (buf), fp) != sizeof (buf))
135     {
136         fseek (fp, savedFilePosition, SEEK_SET);
137         return 0;
138     }
139     if (memcmp (buf, "APETAGEX", 8) != 0) {
140         fseek (fp, savedFilePosition, SEEK_SET);
141         return 0;
142     }
143 
144     fseek (fp, savedFilePosition, SEEK_SET);
145     return (int) is_tag_ape2long (buf + 8);
146 }
147 
148 #define IS_TAG_FOOTER_NOT       0x40000000
149 
150 /**
151     return size of ape tag id3v1 is not counting
152 
153     \param fp File pointer
154     \return Size of ape tag if any, else 0
155 */
156 int
is_ape(FILE * fp)157 is_ape (FILE * fp)
158 {
159     char unsigned buf[32];
160     size_t savedFilePosition;
161 
162     savedFilePosition = ftell (fp);
163     memset (buf, 0, sizeof (buf));
164 
165     fseek (fp, (is_id3v1 (fp) ? -32 - ID3V1_TAG_SIZE : -32), SEEK_END);
166     if (fread (&buf, 1, sizeof (buf), fp) != sizeof (buf))
167     {
168         fseek (fp, savedFilePosition, SEEK_SET);
169         return 0;
170     }
171     if (memcmp (buf, "APETAGEX", 8) != 0) {
172         fseek (fp, savedFilePosition, SEEK_SET);
173         return 0;
174     }
175 
176     fseek (fp, savedFilePosition, SEEK_SET);
177     /* WARNING! macabra code */
178     return (int) (is_tag_ape2long (buf + 8 + 4) +
179         (
180             ( (is_tag_ape2long (buf + 8) == 2000) &&
181             !(is_tag_ape2long (buf + 8 + 4 + 8) & IS_TAG_FOOTER_NOT)
182             ) ? 32 : 0
183         ) /* footer size = 32 */
184         );
185 }
186