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