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