Mercurial > audlegacy-plugins
annotate src/wavpack/tags.cxx @ 3052:95b34f46a231
Comment out MPEG2/MPEG4 determination using the variable id. It is not used anywhere. Code analysis run, unique ID 6nYoHM.
author | Tony Vroon <chainsaw@gentoo.org> |
---|---|
date | Sat, 18 Apr 2009 19:06:20 +0100 |
parents | 3134a0987162 |
children |
rev | line source |
---|---|
109 | 1 #include <stdlib.h> |
2 #include <stdio.h> | |
3 #include <string.h> | |
4 #include <unistd.h> | |
5 #include <fcntl.h> | |
6 #include <wchar.h> | |
2971
3134a0987162
- changed include path from audacious to audlegacy.
Yoshiki Yazawa <yaz@honeyplanet.jp>
parents:
2576
diff
changeset
|
7 #include <audlegacy/plugin.h> |
109 | 8 #include "tags.h" |
9 | |
2233 | 10 static const char* GenreList [] = { |
11 "Blues", "Classic Rock", "Country", "Dance", "Disco", "Funk", "Grunge", | |
12 "Hip-Hop", "Jazz", "Metal", "New Age", "Oldies", "Other", "Pop", "R&B", | |
13 "Rap", "Reggae", "Rock", "Techno", "Industrial", "Alternative", "Ska", | |
14 "Death Metal", "Pranks", "Soundtrack", "Euro-Techno", "Ambient", | |
15 "Trip-Hop", "Vocal", "Jazz+Funk", "Fusion", "Trance", "Classical", | |
16 "Instrumental", "Acid", "House", "Game", "Sound Clip", "Gospel", "Noise", | |
17 "AlternRock", "Bass", "Soul", "Punk", "Space", "Meditative", | |
18 "Instrumental Pop", "Instrumental Rock", "Ethnic", "Gothic", "Darkwave", | |
19 "Techno-Industrial", "Electronic", "Pop-Folk", "Eurodance", "Dream", | |
20 "Southern Rock", "Comedy", "Cult", "Gangsta", "Top 40", "Christian Rap", | |
21 "Pop/Funk", "Jungle", "Native American", "Cabaret", "New Wave", | |
22 "Psychadelic", "Rave", "Showtunes", "Trailer", "Lo-Fi", "Tribal", | |
23 "Acid Punk", "Acid Jazz", "Polka", "Retro", "Musical", "Rock & Roll", | |
24 "Hard Rock", "Folk", "Folk/Rock", "National Folk", "Swing", "Fast-Fusion", | |
25 "Bebob", "Latin", "Revival", "Celtic", "Bluegrass", "Avantgarde", | |
26 "Gothic Rock", "Progressive Rock", "Psychedelic Rock", "Symphonic Rock", | |
27 "Slow Rock", "Big Band", "Chorus", "Easy Listening", "Acoustic", "Humour", | |
28 "Speech", "Chanson", "Opera", "Chamber Music", "Sonata", "Symphony", | |
29 "Booty Bass", "Primus", "Porn Groove", "Satire", "Slow Jam", "Club", | |
30 "Tango", "Samba", "Folklore", "Ballad", "Power Ballad", "Rhythmic Soul", | |
31 "Freestyle", "Duet", "Punk Rock", "Drum Solo", "A capella", "Euro-House", | |
32 "Dance Hall", "Goa", "Drum & Bass", "Club House", "Hardcore", "Terror", | |
33 "Indie", "BritPop", "NegerPunk", "Polsk Punk", "Beat", "Christian Gangsta", | |
34 "Heavy Metal", "Black Metal", "Crossover", "Contemporary C", | |
35 "Christian Rock", "Merengue", "Salsa", "Thrash Metal", "Anime", "JPop", | |
36 "SynthPop" | |
37 }; | |
38 | |
109 | 39 struct APETagFooterStruct { |
40 unsigned char ID[8]; | |
41 unsigned char Version[4]; | |
42 unsigned char Length[4]; | |
43 unsigned char TagCount[4]; | |
44 unsigned char Flags[4]; | |
45 unsigned char Reserved[8]; | |
46 }; | |
47 | |
48 typedef struct { | |
49 char *key; | |
50 size_t keylen; | |
51 unsigned char *value; | |
52 size_t valuelen; | |
53 unsigned int flags; | |
54 } TagItem; | |
55 | |
56 unsigned long | |
57 Read_LE_Uint32(const unsigned char *p) | |
58 { | |
59 return ((unsigned long) p[0] << 0) | | |
60 ((unsigned long) p[1] << 8) | | |
61 ((unsigned long) p[2] << 16) | ((unsigned long) p[3] << 24); | |
62 } | |
63 | |
64 // Convert UTF-8 coded string to UNICODE | |
65 // Return number of characters converted | |
66 int | |
67 utf8ToUnicode(const char *lpMultiByteStr, wchar_t * lpWideCharStr, | |
68 int cmbChars) | |
69 { | |
70 const unsigned char *pmb = (unsigned char *) lpMultiByteStr; | |
71 unsigned short *pwc = (unsigned short *) lpWideCharStr; | |
72 const unsigned char *pmbe; | |
73 size_t cwChars = 0; | |
74 | |
75 if (cmbChars >= 0) { | |
76 pmbe = pmb + cmbChars; | |
77 } | |
78 else { | |
79 pmbe = NULL; | |
80 } | |
81 | |
82 while ((pmbe == NULL) || (pmb < pmbe)) { | |
83 char mb = *pmb++; | |
84 unsigned int cc = 0; | |
85 unsigned int wc; | |
86 | |
87 while ((cc < 7) && (mb & (1 << (7 - cc)))) { | |
88 cc++; | |
89 } | |
90 | |
91 if (cc == 1 || cc > 6) // illegal character combination for UTF-8 | |
92 continue; | |
93 | |
94 if (cc == 0) { | |
95 wc = mb; | |
96 } | |
97 else { | |
98 wc = (mb & ((1 << (7 - cc)) - 1)) << ((cc - 1) * 6); | |
99 while (--cc > 0) { | |
100 if (pmb == pmbe) // reached end of the buffer | |
101 return cwChars; | |
102 mb = *pmb++; | |
103 if (((mb >> 6) & 0x03) != 2) // not part of multibyte character | |
104 return cwChars; | |
105 wc |= (mb & 0x3F) << ((cc - 1) * 6); | |
106 } | |
107 } | |
108 | |
109 if (wc & 0xFFFF0000) | |
110 wc = L'?'; | |
111 *pwc++ = wc; | |
112 cwChars++; | |
113 if (wc == L'\0') | |
114 return cwChars; | |
115 } | |
116 | |
117 return cwChars; | |
118 } | |
119 | |
120 void | |
121 tag_insert(char *buffer, const char *value, long unsigned int len, | |
122 long unsigned int maxlen, bool decode_utf8) | |
123 { | |
124 char *p; | |
125 wchar_t wValue[MAX_LEN]; | |
126 char temp[MAX_LEN]; | |
127 long unsigned int c; | |
128 const wchar_t *src = wValue; | |
129 | |
130 if (len >= maxlen) | |
131 len = maxlen - 1; | |
132 if (decode_utf8) { | |
133 if ((c = utf8ToUnicode(value, wValue, len)) <= 0) | |
134 return; | |
135 if (wValue[c] != L'\0') | |
136 wValue[c++] = L'\0'; | |
137 if ((c = wcsrtombs(temp, &src, MAX_LEN, NULL)) == 0) | |
138 return; | |
139 } | |
140 else { | |
141 c = len; | |
142 strncpy(temp, value, len); | |
143 while (temp[len - 1] == 0x20 || len < 1) { | |
144 len--; | |
145 } | |
146 temp[len] = '\0'; | |
147 } | |
148 | |
149 //if ( *buffer == '\0' ) { // new value | |
150 p = buffer; | |
151 //} else { // append to existing value | |
152 // p = strchr (buffer, '\0' ); | |
153 // p += sprintf ( p, ", " ); | |
154 //} | |
155 | |
156 if ((p - buffer) + c >= maxlen) | |
157 c = maxlen - (p - buffer) - 1; | |
158 strncpy(p, temp, c); | |
159 p[c] = '\0'; | |
160 } | |
161 | |
162 // Returns the Type of Tag (Ape or ID3) | |
163 int | |
265 | 164 GetTageType(VFSFile * fp) |
109 | 165 { |
166 struct APETagFooterStruct T; | |
167 unsigned char tagheader[3]; | |
168 int size; | |
169 | |
170 if (fp == NULL) { | |
171 return TAG_NONE; | |
172 } | |
173 | |
1978 | 174 if (aud_vfs_fseek(fp, 0, SEEK_END) != 0) |
109 | 175 return TAG_NONE; |
1978 | 176 size = aud_vfs_ftell(fp); |
177 if (aud_vfs_fseek(fp, size - sizeof T, SEEK_SET) != 0) | |
109 | 178 return TAG_NONE; |
1978 | 179 if (aud_vfs_fread(&T, 1, sizeof T, fp) != sizeof T) |
109 | 180 return TAG_NONE; |
181 if (memcmp(T.ID, "APETAGEX", sizeof T.ID) == 0) | |
182 return TAG_APE; | |
1978 | 183 if (aud_vfs_fseek(fp, -128L, SEEK_END) != 0) |
109 | 184 return TAG_NONE; |
1978 | 185 if (aud_vfs_fread(tagheader, 1, 3, fp) != 3) |
109 | 186 return TAG_NONE; |
187 if (0 == memcmp(tagheader, "TAG", 3)) | |
188 return TAG_ID3; | |
189 return TAG_NONE; | |
190 } | |
191 | |
192 | |
193 int | |
265 | 194 ReadID3Tag(VFSFile * fp, ape_tag * Tag) |
109 | 195 { |
196 char *tag; | |
197 char *buff; | |
198 unsigned int genre; | |
199 | |
200 buff = (char *) malloc(128); | |
201 | |
202 *(Tag->title) = '\0'; | |
203 *(Tag->artist) = '\0'; | |
204 *(Tag->album) = '\0'; | |
205 *(Tag->comment) = '\0'; | |
206 *(Tag->genre) = '\0'; | |
207 *(Tag->track) = '\0'; | |
208 *(Tag->year) = '\0'; | |
209 | |
1978 | 210 if (aud_vfs_fseek(fp, -128L, SEEK_END) != 0) |
109 | 211 return 0; |
1978 | 212 if (aud_vfs_fread(buff, 1, 128, fp) != 128) |
109 | 213 return 0; |
214 tag = buff; | |
215 tag_insert(Tag->title, (tag + 3), 30, 32, false); | |
216 tag_insert(Tag->artist, (tag + 33), 30, 32, false); | |
217 tag_insert(Tag->album, (tag + 63), 30, 32, false); | |
218 tag_insert(Tag->year, (tag + 93), 4, 32, false); | |
219 tag_insert(Tag->comment, (tag + 97), 30, 32, false); | |
220 genre = (unsigned char) tag[127]; | |
221 if (genre >= sizeof(GenreList) / sizeof(int)) | |
222 genre = 12; | |
223 tag_insert(Tag->genre, GenreList[genre], 30, 32, false); | |
224 sprintf(tag, "%u", tag[126]); | |
225 tag_insert(Tag->track, tag, 30, 32, false); | |
226 free(buff); | |
227 return 1; | |
228 } | |
229 | |
230 // Reads APE v2.0 tag | |
231 int | |
265 | 232 ReadAPE2Tag(VFSFile * fp, ape_tag * Tag) |
109 | 233 { |
234 unsigned long vsize; | |
235 unsigned long isize; | |
236 unsigned long flags; | |
237 unsigned char *buff; | |
238 unsigned char *p; | |
239 unsigned char *end; | |
240 struct APETagFooterStruct T; | |
241 unsigned long TagLen; | |
242 unsigned long TagCount; | |
243 long size; | |
244 | |
245 *(Tag->title) = '\0'; | |
246 *(Tag->artist) = '\0'; | |
247 *(Tag->album) = '\0'; | |
248 *(Tag->comment) = '\0'; | |
249 *(Tag->genre) = '\0'; | |
250 *(Tag->track) = '\0'; | |
251 *(Tag->year) = '\0'; | |
252 | |
1978 | 253 if (aud_vfs_fseek(fp, 0, SEEK_END) != 0) |
109 | 254 return 0; |
1978 | 255 size = aud_vfs_ftell(fp); |
256 if (aud_vfs_fseek(fp, size - sizeof T, SEEK_SET) != 0) | |
109 | 257 return 0; |
1978 | 258 if (aud_vfs_fread(&T, 1, sizeof T, fp) != sizeof T) |
109 | 259 return 0; |
260 if (memcmp(T.ID, "APETAGEX", sizeof T.ID) != 0) | |
261 return 0; | |
262 if (Read_LE_Uint32(T.Version) != 2000) | |
263 return 0; | |
264 TagLen = Read_LE_Uint32(T.Length); | |
265 if (TagLen < sizeof T) | |
266 return 0; | |
1978 | 267 if (aud_vfs_fseek(fp, size - TagLen, SEEK_SET) != 0) |
109 | 268 return 0; |
269 if ((buff = (unsigned char *) malloc(TagLen)) == NULL) | |
270 return 0; | |
1978 | 271 if (aud_vfs_fread(buff, 1, TagLen - sizeof T, fp) != TagLen - sizeof T) { |
109 | 272 free(buff); |
273 return 0; | |
274 } | |
275 | |
276 TagCount = Read_LE_Uint32(T.TagCount); | |
277 end = buff + TagLen - sizeof(T); | |
278 for (p = buff; p < end && TagCount--;) { | |
279 vsize = Read_LE_Uint32(p); | |
280 p += 4; | |
281 flags = Read_LE_Uint32(p); | |
282 p += 4; | |
283 isize = strlen((char *) p); | |
284 | |
285 if (isize > 0 && vsize > 0) { | |
286 if (!(flags & 1 << 1)) { // insert UTF-8 string (skip binary values) | |
287 if (!strcasecmp((char *) p, "Title")) { | |
288 tag_insert(Tag->title, (char *) (p + isize + 1), vsize, | |
289 MAX_LEN, false); | |
290 } | |
291 else if (!strcasecmp((char *) p, "Artist")) { | |
292 tag_insert(Tag->artist, (char *) (p + isize + 1), vsize, | |
293 MAX_LEN, false); | |
294 } | |
295 else if (!strcasecmp((char *) p, "Album")) { | |
296 tag_insert(Tag->album, (char *) (p + isize + 1), vsize, | |
297 MAX_LEN, false); | |
298 } | |
299 else if (!strcasecmp((char *) p, "Comment")) { | |
300 tag_insert(Tag->comment, (char *) (p + isize + 1), vsize, | |
301 MAX_LEN, false); | |
302 } | |
303 else if (!strcasecmp((char *) p, "Genre")) { | |
304 tag_insert(Tag->genre, (char *) (p + isize + 1), vsize, | |
305 MAX_LEN, false); | |
306 } | |
307 else if (!strcasecmp((char *) p, "Track")) { | |
308 tag_insert(Tag->track, (char *) (p + isize + 1), vsize, | |
309 128, false); | |
310 } | |
311 else if (!strcasecmp((char *) p, "Year")) { | |
312 tag_insert(Tag->year, (char *) (p + isize + 1), vsize, | |
313 128, false); | |
314 } | |
315 } | |
316 } | |
317 p += isize + 1 + vsize; | |
318 } | |
319 free(buff); | |
320 return 1; | |
321 } | |
322 | |
323 int | |
324 DeleteTag(char *filename) | |
325 { | |
326 | |
1978 | 327 VFSFile *fp = aud_vfs_fopen(filename, "rb+"); |
109 | 328 int tagtype; |
329 int fd; | |
330 long filelength = 0; | |
331 long dellength = -1; | |
332 char *tagheader; | |
333 unsigned long *apelength; | |
334 int res = -1; | |
335 | |
336 if (fp == NULL) { | |
337 char text[256]; | |
338 | |
339 sprintf(text, "File \"%s\" not found or is read protected!\n", | |
340 filename); | |
1677
f6f5603a0954
xmms_show_message() changed to audacious_info_dialog()
Matti Hamalainen <ccr@tnsp.org>
parents:
1159
diff
changeset
|
341 audacious_info_dialog("File-Error", (gchar *) text, "Ok", FALSE, NULL, |
109 | 342 NULL); |
343 return -1; | |
344 } | |
345 tagtype = GetTageType(fp); | |
346 | |
347 // get Length of File | |
1978 | 348 aud_vfs_fseek(fp, 0L, SEEK_END); |
349 filelength = aud_vfs_ftell(fp); | |
109 | 350 |
351 apelength = (unsigned long *) malloc(4); | |
352 tagheader = (char *) malloc(9); | |
353 | |
354 if (tagtype == TAG_ID3) { | |
355 dellength = 128L; | |
356 } | |
357 else if (tagtype == TAG_APE) { | |
1978 | 358 aud_vfs_fseek(fp, -32L, SEEK_END); |
359 aud_vfs_fread(tagheader, 8, 1, fp); | |
109 | 360 if (0 == memcmp(tagheader, "APETAGEX", 8)) { |
1978 | 361 aud_vfs_fseek(fp, -20L, SEEK_END); |
362 aud_vfs_fread(apelength, 4, 1, fp); | |
109 | 363 dellength = *apelength + 32; |
364 } | |
365 } | |
366 | |
367 | |
368 if (dellength > -1) //if TAG was found, delete it | |
369 { | |
370 fd = open(filename, O_RDWR); | |
371 res = ftruncate(fd, (off_t) (filelength - dellength)); | |
372 close(fd); | |
373 } | |
374 | |
375 free(tagheader); | |
376 free(apelength); | |
377 | |
378 //returns 0 if everything is ok | |
379 return res; | |
380 } | |
381 | |
382 // Returns bytes used in APE-Tag for this value | |
383 int | |
1044
b1128efde471
[svn] - get rid of all warnings gcc 4.2.0 emits with my build configuration.
yaz
parents:
265
diff
changeset
|
384 addValue(TagItem * item, const char *key, char *value) |
109 | 385 { |
386 item->keylen = strlen(key); | |
387 item->valuelen = strlen(value); | |
388 item->key = (char *) malloc(item->keylen + 1); | |
389 item->value = (unsigned char *) malloc(item->valuelen + 1); | |
390 strcpy((char *) item->value, value); | |
391 strcpy(item->key, key); | |
392 item->flags = 0; | |
393 return (9 + item->keylen + item->valuelen); | |
394 } | |
395 | |
396 int | |
397 WriteAPE2Tag(char *filename, ape_tag * Tag) | |
398 { | |
265 | 399 VFSFile *fp; |
109 | 400 unsigned char H[32] = "APETAGEX"; |
401 unsigned long Version = 2000; | |
402 unsigned char dw[8]; | |
403 unsigned long estimatedbytes = 32; // 32 byte footer + all items, these are the 32 bytes footer, the items are added later | |
404 long writtenbytes = -32; // actually writtenbytes-32, which should be equal to estimatedbytes (= footer + all items) | |
405 unsigned int TagCount = 0; | |
406 TagItem T[7]; | |
407 | |
408 | |
409 // Delete Tag if there is one | |
1978 | 410 fp = aud_vfs_fopen(filename, "rb+"); |
109 | 411 if (fp == NULL) { |
412 char text[256]; | |
413 | |
1159 | 414 snprintf(text, 256, "File \"%s\" not found or is read protected!\n", |
109 | 415 filename); |
1677
f6f5603a0954
xmms_show_message() changed to audacious_info_dialog()
Matti Hamalainen <ccr@tnsp.org>
parents:
1159
diff
changeset
|
416 audacious_info_dialog("File-Error", (gchar *) text, "Ok", FALSE, NULL, |
109 | 417 NULL); |
418 return -1; | |
419 } | |
420 | |
421 int tagtype = GetTageType(fp); | |
422 | |
423 if (tagtype != TAG_NONE) | |
424 if (DeleteTag(filename) != 0) | |
425 return 0; | |
426 | |
427 // Produce TagItem-Array | |
428 if (strlen(Tag->title) > 0) { | |
429 char *value = (char *) malloc(strlen(Tag->title) + 1); | |
430 | |
431 strcpy(value, Tag->title); | |
432 int res = addValue(&T[TagCount], "Title", value); | |
433 | |
434 estimatedbytes += res; | |
435 if (res > 0) | |
436 TagCount++; | |
437 free(value); | |
438 } | |
439 | |
440 if (strlen(Tag->artist) > 0) { | |
441 char *value = (char *) malloc(strlen(Tag->artist) + 1); | |
442 | |
443 strcpy(value, Tag->artist); | |
444 int res = addValue(&T[TagCount], "Artist", value); | |
445 | |
446 estimatedbytes += res; | |
447 if (res > 0) | |
448 TagCount++; | |
449 free(value); | |
450 } | |
451 | |
452 if (strlen(Tag->album) > 0) { | |
453 char *value = (char *) malloc(strlen(Tag->album) + 1); | |
454 | |
455 strcpy(value, Tag->album); | |
456 int res = addValue(&T[TagCount], "Album", value); | |
457 | |
458 estimatedbytes += res; | |
459 if (res > 0) | |
460 TagCount++; | |
461 free(value); | |
462 } | |
463 | |
464 if (strlen(Tag->comment) > 0) { | |
465 char *value = (char *) malloc(strlen(Tag->comment) + 1); | |
466 | |
467 strcpy(value, Tag->comment); | |
468 int res = addValue(&T[TagCount], "Comment", value); | |
469 | |
470 estimatedbytes += res; | |
471 if (res > 0) | |
472 TagCount++; | |
473 free(value); | |
474 } | |
475 | |
476 if (strlen(Tag->genre) > 0) { | |
477 char *value = (char *) malloc(strlen(Tag->genre) + 1); | |
478 | |
479 strcpy(value, Tag->genre); | |
480 int res = addValue(&T[TagCount], "Genre", value); | |
481 | |
482 estimatedbytes += res; | |
483 if (res > 0) | |
484 TagCount++; | |
485 free(value); | |
486 } | |
487 | |
488 if (strlen(Tag->track) > 0) { | |
489 char *value = (char *) malloc(strlen(Tag->track) + 1); | |
490 | |
491 strcpy(value, Tag->track); | |
492 int res = addValue(&T[TagCount], "Track", value); | |
493 | |
494 estimatedbytes += res; | |
495 if (res > 0) | |
496 TagCount++; | |
497 free(value); | |
498 } | |
499 | |
500 if (strlen(Tag->year) > 0) { | |
501 char *value = (char *) malloc(strlen(Tag->year) + 1); | |
502 | |
503 strcpy(value, Tag->year); | |
504 int res = addValue(&T[TagCount], "Year", value); | |
505 | |
506 estimatedbytes += res; | |
507 if (res > 0) | |
508 TagCount++; | |
509 free(value); | |
510 } | |
511 // Start writing the new Ape2 Tag | |
1978 | 512 aud_vfs_fseek(fp, 0L, SEEK_END); |
109 | 513 |
514 if (TagCount == 0) { | |
515 printf("no tag to write"); | |
516 return 0; | |
517 } | |
518 | |
519 if (estimatedbytes >= 8192 + 103) { | |
520 printf | |
521 ("\nTag is %.1f Kbyte long. This is longer than the maximum recommended 8 KByte.\n\a", | |
522 estimatedbytes / 1024.); | |
523 return 0; | |
524 } | |
525 | |
526 H[8] = Version >> 0; | |
527 H[9] = Version >> 8; | |
528 H[10] = Version >> 16; | |
529 H[11] = Version >> 24; | |
530 H[12] = estimatedbytes >> 0; | |
531 H[13] = estimatedbytes >> 8; | |
532 H[14] = estimatedbytes >> 16; | |
533 H[15] = estimatedbytes >> 24; | |
534 H[16] = TagCount >> 0; | |
535 H[17] = TagCount >> 8; | |
536 H[18] = TagCount >> 16; | |
537 H[19] = TagCount >> 24; | |
538 | |
539 H[23] = 0x80 | 0x20; | |
1978 | 540 writtenbytes += aud_vfs_fwrite(H, 1, 32, fp); |
109 | 541 |
542 for (unsigned int i = 0; i < TagCount; i++) { | |
543 dw[0] = T[i].valuelen >> 0; | |
544 dw[1] = T[i].valuelen >> 8; | |
545 dw[2] = T[i].valuelen >> 16; | |
546 dw[3] = T[i].valuelen >> 24; | |
547 dw[4] = T[i].flags >> 0; | |
548 dw[5] = T[i].flags >> 8; | |
549 dw[6] = T[i].flags >> 16; | |
550 dw[7] = T[i].flags >> 24; | |
1978 | 551 writtenbytes += aud_vfs_fwrite(dw, 1, 8, fp); |
552 writtenbytes += aud_vfs_fwrite(T[i].key, 1, T[i].keylen, fp); | |
553 writtenbytes += aud_vfs_fwrite("", 1, 1, fp); | |
109 | 554 if (T[i].valuelen > 0) |
1978 | 555 writtenbytes += aud_vfs_fwrite(T[i].value, 1, T[i].valuelen, fp); |
109 | 556 } |
557 | |
558 H[23] = 0x80; | |
1978 | 559 writtenbytes += aud_vfs_fwrite(H, 1, 32, fp); |
109 | 560 |
561 if (estimatedbytes != (unsigned long) writtenbytes) | |
562 printf("\nError writing APE tag.\n"); | |
1978 | 563 aud_vfs_fclose(fp); |
109 | 564 TagCount = 0; |
565 return 0; | |
566 } |