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 <math.h>
29 #ifndef __BORLANDC__
30 # include <unistd.h>
31 #endif
32 #include <glib/gstdio.h>
33 #include "apetaglib.h"
34 #include "../id3_tag.h"
35 #include "../genres.h"
36 #include "../win32/win32dep.h"
37
38 #include "is_tag.h"
39 #ifdef ID3V2_READ
40 # include "id3v2_read.h"
41 #endif
42
43 /* LOCAL STRUCTURES */
44
45 /**
46 \struct _apetag_footer
47 \brief structure of APETAGEXT footer or/and header tag
48 */
49 struct _apetag_footer
50 {
51 unsigned char id[8]; /**< magic should equal 'APETAGEX' */
52 unsigned char version[4]; /**< version 1000 (v1.0) or 2000 (v 2.0) */
53 unsigned char length[4]; /**< the complete size of the tag, including footer, but no header for v2.0 */
54 unsigned char tagCount[4]; /**< the number of fields in the tag */
55 unsigned char flags[4]; /**< the tag flags (none currently defined for v 1.0) */
56 unsigned char reserved[8]; /**< reserved for later use */
57 };
58
59 /**
60 \struct _ape_mem_cnt
61 \brief internal structure for apetag
62 */
63 struct _ape_mem_cnt
64 {
65 struct tag **tag;
66 int countTag;
67 int memTagAlloc; // for mem container;
68 char *filename; // for info
69 struct _apetag_footer ape_header;
70 struct _apetag_footer ape_footer;
71 int currentPosition;
72 };
73
74 /* *
75 \struct _id3v1Tag
76 \brief for id3v1 tag
77 */
78 struct _id3v1Tag
79 {
80 char magic[3]; // `TAG`
81 char title[30];
82 char artist[30];
83 char album[30];
84 char year[4];
85 char comment[30]; // if ([28]==0 and [29]!=0) track = [29]
86 unsigned char genre;
87 };
88
89 /* LOCAL FUNCTION prototypes */
90 unsigned long
91 ape2long (unsigned char *p);
92 void
93 long2ape (unsigned char *p, const unsigned long value);
94 struct tag *
95 libapetag_maloc_cont_int (apetag *mem_cnt, struct tag *mTag);
96 int
97 libapetag_maloc_cont_text (apetag *mem_cnt, unsigned long flags,
98 long sizeName, const char *name, long sizeValue, char *value);
99 int
100 libapetag_maloc_cont (apetag *mem_cnt, unsigned long flags,
101 long sizeName, const char *name, long sizeValue, const char *value);
102 static int
103 libapetag_qsort (struct tag **a, struct tag **b);
104 int
105 make_id3v1_tag(apetag *mem_cnt, struct _id3v1Tag *m);
106
107
108 unsigned long
ape2long(unsigned char * p)109 ape2long (unsigned char *p)
110 {
111 return (((unsigned long) p[0] << 0) |
112 ((unsigned long) p[1] << 8) |
113 ((unsigned long) p[2] << 16) |
114 ((unsigned long) p[3] << 24) );
115 }
116
117 void
long2ape(unsigned char * p,const unsigned long value)118 long2ape (unsigned char *p, const unsigned long value)
119 {
120 p[0] = (unsigned char) (value >> 0);
121 p[1] = (unsigned char) (value >> 8);
122 p[2] = (unsigned char) (value >> 16);
123 p[3] = (unsigned char) (value >> 24);
124 }
125
126
127 /*
128 PL: funkcja troszczaca sie o odpowiednią ilosc zalokowanej pamieci dla tablicy
129 PL: %mTag% przy okazji alokuje z wyprzedzeniem troche wiecej pamieci [mniej %realoc%]
130 PL: zwraca %mTag[]%
131 :NON_USER:!!!
132 */
133 #define LIBAPETAG_MEM_ALLOC_AHEAD 16 /* 15 it's good for normal #of tag, Aver 4-8 */
134 struct tag *
libapetag_maloc_cont_int(apetag * mem_cnt,struct tag * mTag)135 libapetag_maloc_cont_int (apetag *mem_cnt, struct tag *mTag)
136 {
137 struct tag **tag_tmp = mem_cnt->tag;
138
139 if (mem_cnt->memTagAlloc == 0) { /* init */
140 mem_cnt->tag = (struct tag **) malloc ((sizeof (struct tag *) * LIBAPETAG_MEM_ALLOC_AHEAD));
141 mem_cnt->memTagAlloc = LIBAPETAG_MEM_ALLOC_AHEAD;
142 mem_cnt->countTag = 0;
143 if (mem_cnt->tag == NULL) {
144 mem_cnt->memTagAlloc = mem_cnt->countTag = 0;
145 PRINT_ERR ( "ERROR->libapetag->libapetag_maloc_cont_int:malloc\n");
146 return NULL;
147 }
148 }
149
150 if ((mem_cnt->memTagAlloc) <= (mem_cnt->countTag + 1)) {
151 mem_cnt->tag = (struct tag **) realloc (mem_cnt->tag, (sizeof (struct tag *) *
152 (mem_cnt->memTagAlloc + LIBAPETAG_MEM_ALLOC_AHEAD)));
153 mem_cnt->memTagAlloc += LIBAPETAG_MEM_ALLOC_AHEAD;
154 }
155
156 if (mem_cnt->tag == NULL) {
157 int n;
158
159 PRINT_ERR ( "ERROR->libapetag->libapetag_maloc_cont_int:malloc\n");
160 /* free old all */
161 for (n = mem_cnt->countTag-1; n >= 0; n--) {
162 free (tag_tmp[n]->value);
163 free (tag_tmp[n]->name);
164 free (tag_tmp[n]);
165 }
166 free (tag_tmp);
167 mem_cnt->memTagAlloc = mem_cnt->countTag = 0;
168 return NULL;
169 }
170
171 mem_cnt->tag[mem_cnt->countTag] = mTag;
172 mem_cnt->countTag++;
173 return mTag;
174
175 }
176 #undef LIBAPETAG_MEM_ALLOC_AHEAD
177
178
179 /*
180 PL: alocuje pamiec dla %mTag% przypisuje odpowiednio wartosci
181 PL: dodaje %\0% do stringów [na wszelki wypadek]
182 PL: nie dopisuje takich samych
183 PL: wszystkie sizy maja byc bez \0 (jak bedzie to doliczy jeszcze jeden)
184 :NON_USER:!!!
185 */
186 int
libapetag_maloc_cont(apetag * mem_cnt,unsigned long flags,long sizeName,const char * name,long sizeValue,const char * value)187 libapetag_maloc_cont (apetag *mem_cnt, unsigned long flags,
188 long sizeName, const char *name, long sizeValue, const char *value)
189 {
190 struct tag *mTag;
191 // TODO:: zadbac o to zeby tu czyscilo istniejace tagi jesli value=NULL
192 if (!sizeName || !sizeValue)
193 return ATL_BADARG;
194
195 if (apefrm_getstr (mem_cnt, name) == NULL) {
196 mTag = (struct tag *) malloc (sizeof (struct tag));
197
198 if (mTag == NULL)
199 return ATL_MALOC;
200
201 mTag->value = (char *) malloc (sizeValue + 1);
202 if (mTag->value==NULL) {
203 free (mTag);
204 return ATL_MALOC;
205 }
206
207 mTag->name = (char *) malloc (sizeName + 1);
208 if (mTag->name==NULL) {
209 free (mTag->value);
210 free (mTag);
211 return ATL_MALOC;
212 }
213
214 memcpy (mTag->value, value, sizeValue);
215 memcpy (mTag->name, name, sizeName);
216 mTag->value[sizeValue] = '\0';
217 mTag->name[sizeName] = '\0';
218 mTag->sizeName = sizeName;
219 mTag->sizeValue = sizeValue;
220 mTag->flags = flags;
221
222 if (libapetag_maloc_cont_int (mem_cnt, mTag)==NULL) {
223 PRINT_ERR(">apetaglib>libapetag_maloc_cont>> int==NULL");
224 return ATL_MALOC;
225 }
226 }
227
228 return 0;
229 }
230
231 /*
232 PL: jezeli nie istnieje to dodaje taga, pomija ostatnie biale znaki
233 PL: pomija jesli pusty
234 PL: ! zmienia tekst wejściowy
235 :NON_USER:!!!
236 */
237 int
libapetag_maloc_cont_text(apetag * mem_cnt,unsigned long flags,long sizeName,const char * name,long sizeValue,char * value)238 libapetag_maloc_cont_text (apetag *mem_cnt, unsigned long flags,
239 long sizeName, const char *name, long sizeValue,
240 char *value)
241 {
242 int n = sizeValue;
243
244 if (value != NULL && value[0] != '\0' && apefrm_getstr (mem_cnt, name) == NULL) {
245 while (value[--n] == ' ' || value[n] == '\0' || value[n] == '\n') {
246 value[n] = '\0';
247 }
248 return libapetag_maloc_cont (mem_cnt, flags, sizeName, name, n + 1, value);
249 }
250
251 return 0;
252 }
253
254
255 /*
256 PL: dodaje taga do istniejeacych o ustawionych wartosciach %flag% %name% i %value%
257 PL: wylicza odpowiednio rozmiary przy pomocy strlen!!
258 PL: wraper na %libapetag_maloc_cont%
259 PL: wszystko kopiuje sobie do pamieci
260 PL: musi byc juz w UTF-8 dla v2
261 PL: Nadpisuje istniejace
262 */
263 /**
264 \brief Add text frame
265
266 add text frame/field to object apetag (if exist then overwrite)
267
268 \param mem_cnt object #apetag
269 \param flags flags stored in frame
270 \param name name of frame
271 \param value value of frame
272 \return 0 - OK else check #atl_return
273 */
274 int
apefrm_add(apetag * mem_cnt,unsigned long flags,const char * name,const char * value)275 apefrm_add (apetag *mem_cnt, unsigned long flags, const char *name,
276 const char *value)
277 {
278 apefrm_remove_real (mem_cnt, name);
279 return libapetag_maloc_cont (mem_cnt, flags, strlen (name), name, strlen (value), value);
280 }
281
282 /*
283 PL: Prosty wraperek na maloc_cont - do zapisu binarnych
284 */
285 /**
286 \brief add binary frame
287
288 add binary frame/field to object apetag (if exist then overwrite)
289
290 \param mem_cnt object #apetag
291 \param flags flags stored in frame
292 \param sizeName size of name
293 \param name name of frame
294 \param sizeValue size of value
295 \param value value of frame
296 \return 0 - OK else check #atl_return
297 */
298 int
apefrm_add_bin(apetag * mem_cnt,unsigned long flags,long sizeName,char * name,long sizeValue,char * value)299 apefrm_add_bin (apetag *mem_cnt, unsigned long flags,
300 long sizeName, char *name,
301 long sizeValue, char *value)
302 {
303 apefrm_remove_real (mem_cnt, name);
304 return libapetag_maloc_cont (mem_cnt, flags, sizeName, name, sizeValue, value);
305 }
306
307 /*
308 PL: jak %apefrm_add ()% z tym ze nie nadpisuje istniejacych
309 */
310 /**
311 \brief add frame if other (the same name) no exist
312
313 if exist "name" in ape_mem then do nothing else add frame/field to ape_mem
314
315 \param mem_cnt object #apetag
316 \param flags flags stored in frame
317 \param name name of frame
318 \param value value of frame
319 \return 0 - OK else check #atl_return
320 */
321 int
apefrm_add_noreplace(apetag * mem_cnt,unsigned long flags,char * name,char * value)322 apefrm_add_noreplace (apetag *mem_cnt, unsigned long flags,
323 char *name, char *value)
324 {
325 if ( apefrm_getstr (mem_cnt, name) == NULL )
326 return apefrm_add (mem_cnt, flags, name, value);
327
328 return 0;
329 }
330
331 /*
332 PL: wyszukuje taga o nazwie %name% i zwraca structure %struct tag%
333 PL: %APE_TAG_LIB_FIRST% i %APE_TAG_LIB_NEXT% to ulatwienie dla
334 PL: przesukiwania wszystkich istniejacych tagów
335 PL: %APE_TAG_LIB_FIRST% ustawia znacznik na pierwszy tag [0] i zwraca jego wartość
336 PL: %APE_TAG_LIB_NEXT% podaje nastepny tag i zwieksza znacznik, po ostatnim funkcja zwraca %NULL%
337 PL: UWAGA!!! zwraca pointer do wewnetrznej struktury
338 PL: niczego nie zmieniac i nie free()-jowac skopiowac i dopiero
339 PL: zwraca teksty w UTF-8
340 */
341 /**
342 \brief search in apetag for name and return tag
343
344 2 special names \a APE_TAG_LIB_FIRST and \a APE_TAG_LIB_NEXT.
345 FIRST return first frame and set counter to 1
346 NEXT return ++counter frame
347 \code
348 for ((framka = apefrm_get(ape, APE_TAG_LIB_FIRST)); framka!=NULL;) {
349 do_something();
350 framka = apefrm_get(ape, APE_TAG_LIB_NEXT);
351 }
352 \endcode
353 return NULL if no more frame exist
354
355 \param mem_cnt object #apetag
356 \param name frame name for search
357 \return pointer to struct tag if name exist or NULL if don't
358 \warning don't change anything in this struct make copy and work
359 */
360 struct tag *
apefrm_get(apetag * mem_cnt,const char * name)361 apefrm_get (apetag *mem_cnt, const char *name)
362 {
363 int n;
364 struct tag **mTag;
365
366 mTag = (mem_cnt->tag);
367
368 if (mem_cnt->countTag == 0)
369 return NULL;
370
371 if (strcmp (name, APE_TAG_LIB_FIRST) == 0) {
372 mem_cnt->currentPosition = 0;
373 return (mTag[mem_cnt->currentPosition++]);
374 }
375
376 if (strcmp (name, APE_TAG_LIB_NEXT) == 0) {
377 if (mem_cnt->currentPosition >= mem_cnt->countTag)
378 return NULL;
379 return (mTag[mem_cnt->currentPosition++]);
380 }
381
382 for (n = 0; (mem_cnt->countTag) > n; n++) {
383 if (strcasecmp (mTag[n]->name, name) == 0) {
384 return (mTag[n]);
385 }
386 }
387
388 return NULL;
389 }
390
391 /*
392 PL:zwraca %mem_cnt->tag[x]->value% o ile znajdzie nazwe %name% taga
393 PL: prosty wraper na %apefrm_get %
394 PL: UWAGA zwraca pointer z wewnetrznych struktur niczego bezposrednio nie zmieniac
395 PL: i nie free()-jowac bo sie rozsypie
396 PL: zwraca tekst w UTF-8
397 */
398 /**
399 \brief search in apetag for name and return string
400
401 \param mem_cnt object #apetag
402 \param name frame name for search
403 \return pointer to value of frame if name exist or NULL if don't
404 \warning don't change that string make copy before any action
405 \todo check if frame type isn't binary
406 */
407 char *
apefrm_getstr(apetag * mem_cnt,const char * name)408 apefrm_getstr (apetag *mem_cnt, const char *name)
409 {
410 struct tag *mTag;
411
412 mTag = apefrm_get (mem_cnt, name);
413
414 if (mTag == NULL)
415 return NULL;
416
417 return (mTag->value);
418 }
419
420 /*
421 PL: usuwanie taga o nazwie zdefiniowanej w %name%
422 PL:lub wszystkich jezeli %name%=%APE_TAG_LIB_DEL_ALL%
423 PL:UWAGA mozna to napisac inaczej (sprawdzanie czy %name% OR %%special%) ale to w v1.0
424 */
425 /**
426 \brief remove frame from memory
427
428 (real) remove frame from ape_mem.
429 Check #apefrm_remove for more info
430
431 \param mem_cnt object #apetag
432 \param name frame name for search and remove
433 */
434 void
apefrm_remove_real(apetag * mem_cnt,const char * name)435 apefrm_remove_real (apetag *mem_cnt, const char *name)
436 {
437 int n;
438 struct tag **mTag;
439
440 mTag = (mem_cnt->tag);
441
442 /* Delete all */
443 if (strcmp (name, APE_TAG_LIB_DEL_ALL) == 0) {
444 for (n = mem_cnt->countTag-1; n >= 0; n--) {
445 free (mTag[n]->name);
446 free (mTag[n]->value);
447 free (mTag[n]);
448 --mem_cnt->countTag;
449 }
450 return;
451 }
452 /* Delete only one */
453 for (n = mem_cnt->countTag-1; n >= 0; n--) {
454 if (strcasecmp (mTag[n]->name, name) == 0) {
455 free (mTag[n]->name);
456 free (mTag[n]->value);
457 free (mTag[n]);
458 mTag[n] = mTag[mem_cnt->countTag];
459 --mem_cnt->countTag;
460 /* !no return; search for all */
461 }
462 }
463
464 return;
465 }
466 /*
467 PL: tak jakby frejuje framke oznacza do kasacji jednak tego nie robi
468 PL: mechanizm ten głownie jest wykorzystywany do wczytania innych tagów
469 PL: poza wczesniej zkasowanymi aby to usunąc uzyj apefrm_remove_real
470 */
471 /**
472 \brief set frame to remove
473
474 Create fake name and empty value (and set don't save flag).
475 If you use apefrm_add_norepleace then you don't change
476 this not_save_flag.
477 Only apefrm_add overwrite this.
478 [it's for id3v1 but you may using this for remove frames]
479
480 \param mem_cnt object #apetag
481 \param name frame name for search and remove
482 */
483 void
apefrm_remove(apetag * mem_cnt,const char * name)484 apefrm_remove (apetag *mem_cnt, const char *name)
485 {
486 int n;
487 struct tag **mTag;
488
489 apefrm_add (mem_cnt, 0 , name, "delete me");
490
491 mTag = (mem_cnt->tag);
492
493 for (n = 0; (mem_cnt->countTag) > n; n++) {
494 if (strcasecmp (mTag[n]->name, name) == 0) {
495 mTag[n]->sizeValue=0;
496 return;
497 }
498 }
499
500 return;
501 }
502
503 /*
504 PL:Wypisuje na ekran wszystko to co potrzebne do debugu
505 :NON_USER:!!!
506 */
507 /**
508 debug function print all tags exclude bin (print only size for bin)
509 */
510 void
libapetag_print_mem_cnt(apetag * mem_cnt)511 libapetag_print_mem_cnt (apetag *mem_cnt)
512 {
513 int n;
514 struct tag **mTag;
515
516 mTag = (mem_cnt->tag);
517 for (n = 0; (mem_cnt->countTag) > n; n++) {
518 if ( (mTag[n]->flags & ~ITEM_TEXT) == 0 ||
519 (mTag[n]->flags & ~ITEM_LINK) == 0 ) {
520 printf (">apetaglib>PRINT>>F=%lu SN=%li SV=%li N[%s] V[%s]\n",
521 mTag[n]->flags,
522 (long) mTag[n]->sizeName, (long) mTag[n]->sizeValue,
523 mTag[n]->name, mTag[n]->value);
524 } else {
525 printf (">apetaglib>PRINT>>F=%lu SN=%li SV=%li N[%s] V=BINARY\n",
526 mTag[n]->flags,
527 (long) mTag[n]->sizeName, (long) mTag[n]->sizeValue,
528 mTag[n]->name);
529 }
530 }
531
532 return;
533 }
534
535 /*
536 PL: alokuje pamiec dla glównej struktury %struct ape_mem_cnt%
537 PL: i zeruje wszystko co trzeba
538 PL: z jakiegos powodu (mojej niewiedzy) memset nie dziala
539 PL: a w sumie dziala czyszczac troche za duzo
540 */
541 /**
542 \brief initialise new object #apetag and return
543 \return new initialised object #apetag
544 */
545 apetag *
apetag_init(void)546 apetag_init (void)
547 {
548 apetag * mem_cnt;
549
550 mem_cnt = (apetag *) malloc (sizeof (apetag));
551 if (mem_cnt == NULL) {
552 PRINT_ERR ("ERROR->libapetag->apetag_init:malloc\n");
553 return NULL;
554 }
555 mem_cnt->memTagAlloc = 0;
556 mem_cnt->countTag = 0;
557 mem_cnt->filename = NULL;
558 mem_cnt->currentPosition = 0;
559 mem_cnt->tag = NULL;
560
561 return mem_cnt;
562 }
563
564 /*
565 PL: Czysci z sila wodospadu wszystko co zostalo do czyszczenia
566 PL: z %struct ape_mem_cnt% wlacznie, wcześniej to nie było jasne
567 */
568 /**
569 \brief free all work
570 \param mem_cnt object #apetag
571 */
572 void
apetag_free(apetag * mem_cnt)573 apetag_free (apetag *mem_cnt)
574 {
575 int n;
576
577 for (n = mem_cnt->countTag-1; n >= 0; n--)
578 {
579 free (mem_cnt->tag[n]->value);
580 free (mem_cnt->tag[n]->name);
581 free (mem_cnt->tag[n]);
582 }
583 free (mem_cnt->tag);
584 free (mem_cnt);
585 mem_cnt = NULL;
586
587 return;
588
589 }
590
591
592 /**
593 \brief read id3v1 and add frames
594
595 read id3v1 and add frames to ape_mem.
596 Using #apefrm_add_norepleace
597
598 \param mem_cnt object #apetag
599 \param fp file pointer
600 \return 0 - OK else check #atl_return
601 */
602 int
readtag_id3v1_fp(apetag * mem_cnt,FILE * fp)603 readtag_id3v1_fp (apetag *mem_cnt, FILE * fp)
604 {
605 struct _id3v1Tag m;
606
607 if (!is_id3v1(fp))
608 return 0; /* TODO:: 0 or no_id3v1*/
609
610 fseek (fp, -ID3V1_TAG_SIZE, SEEK_END);
611 if (sizeof (struct _id3v1Tag)!=fread(&m, 1, sizeof (struct _id3v1Tag), fp)){
612 PRINT_ERR( "ERROR->libapetag->readtag_id3v1_fp:fread\n");
613 return ATL_FREAD;
614 }
615
616 libapetag_maloc_cont_text(mem_cnt, 0, 5, "Title", 30, m.title);
617 libapetag_maloc_cont_text(mem_cnt, 0, 6, "Artist", 30, m.artist);
618 libapetag_maloc_cont_text(mem_cnt, 0, 5, "Album", 30, m.album);
619 libapetag_maloc_cont_text(mem_cnt, 0, 4, "Year", 4, m.year);
620 if (m.comment[28] == 0 && m.comment[29] != 0) {
621 char track[20];
622 snprintf(track, 19, "%i", m.comment[29]);
623 libapetag_maloc_cont_text(mem_cnt, 0, 5, "Track", strlen(track), track);
624 libapetag_maloc_cont_text(mem_cnt, 0, 7, "Comment", 28, m.comment);
625 } else {
626 libapetag_maloc_cont_text(mem_cnt, 0, 7, "Comment", 30, m.comment);
627 }
628 /* Special-case the genre. As the text never has a trailing space, which
629 * libapetag_maloc_cont_text() strips, simply call libapetag_maloc_cont()
630 * directly. */
631 libapetag_maloc_cont(mem_cnt, 0, 5, "Genre",
632 strlen(genre_no(m.genre)), genre_no(m.genre));
633
634 return 0;
635 }
636
637 /*
638 PL: wczytuje odpowiednie fra(mk)gi do pamieci w razie koniecznosci przyciecia
639 PL: dodaje "..." na koniec
640 PL: TODO genre
641
642 PL: macro COMPUTE_ID3V1_TAG
643 */
644 #define COMPUTE_ID3V1_TAG(FramkA, TagNamE, SizE, TagValuE) \
645 FramkA = apefrm_get(mem_cnt, TagNamE); \
646 if (FramkA != NULL) { \
647 memcpy (TagValuE, FramkA->value, \
648 ((FramkA->sizeValue) > SizE) ? SizE : FramkA->sizeValue ); \
649 if ((FramkA->sizeValue) > SizE) { \
650 TagValuE[SizE-1]='.'; TagValuE[SizE-2]='.'; TagValuE[SizE-3]='.'; \
651 } \
652 }
653
654 int
make_id3v1_tag(apetag * mem_cnt,struct _id3v1Tag * m)655 make_id3v1_tag(apetag *mem_cnt, struct _id3v1Tag *m)
656 {
657 struct tag * framka;
658
659 if (m == NULL)
660 return ATL_BADARG;
661
662 memset(m, '\0', sizeof(struct _id3v1Tag));
663
664 memcpy (m->magic,"TAG",3);
665 COMPUTE_ID3V1_TAG(framka, "Title", 30, m->title);
666 COMPUTE_ID3V1_TAG(framka, "Artist", 30, m->artist);
667 COMPUTE_ID3V1_TAG(framka, "Album", 30, m->album);
668 COMPUTE_ID3V1_TAG(framka, "Year", 4, m->year);
669
670 if ((framka=apefrm_get(mem_cnt, "Track"))!=NULL) {
671 m->comment[29]=(unsigned char) atoi(framka->value);
672 m->comment[28]='\0';
673 COMPUTE_ID3V1_TAG(framka, "Comment", 28, m->comment);
674 } else {
675 COMPUTE_ID3V1_TAG(framka, "Comment", 30, m->comment);
676 }
677
678 return 0;
679 }
680
681 /*
682 PL: silnik tego liba
683 PL: %filename% jest w tej chwili tylko dla id3v2 f..k
684 PL: %ape_mem_cnt% moze byc nie zainicjalizowany ale wtedy musi byc = NULL
685 */
686 /**
687 \brief read file and add frames
688
689 \param mem_cnt object #apetag
690 \param filename
691 \param fp
692 \param flag
693 \return 0 - OK else check #atl_return
694 */
695 int
apetag_read_fp(apetag * mem_cnt,FILE * fp,const char * filename,int flag)696 apetag_read_fp(apetag *mem_cnt, FILE * fp, const char *filename, int flag)
697 {
698 int id3v1 = 0;
699 int apeTag2 = 0;
700 unsigned char *buff;
701 struct _apetag_footer ape_footer;
702 size_t savedFilePosition, buffLength;
703
704 unsigned char *end;
705 unsigned long tagCount;
706 unsigned char *p;
707
708 savedFilePosition = ftell(fp);
709
710 id3v1 = is_id3v1(fp);
711
712 if (mem_cnt == NULL) {
713 PRINT_ERR( ">apetaglib>READ_FP>FATAL>apetag_init()\n");
714 fseek(fp, savedFilePosition, SEEK_SET);
715 return ATL_NOINIT;
716 }
717
718 fseek (fp, id3v1 ? -ID3V1_TAG_SIZE - sizeof (ape_footer)
719 : -sizeof (ape_footer), SEEK_END);
720 if (sizeof (ape_footer) != fread(&ape_footer, 1, sizeof (ape_footer), fp)){
721 PRINT_ERR( "ERROR->libapetag->apetag_read_fp:fread1\n");
722 fseek(fp, savedFilePosition, SEEK_SET);
723 return ATL_FREAD;
724 }
725
726 if (!(flag & DONT_READ_TAG_APE) &&
727 (memcmp(ape_footer.id, "APETAGEX", sizeof (ape_footer.id)) == 0))
728 {
729 PRINT_D9(">apetaglib>READ_FP>>%s: ver %li len %li # %li fl %lx v1=%i v2=%i ape=%i[v%i]\n",
730 filename, ape2long(ape_footer.version),
731 ape2long(ape_footer.length),
732 ape2long(ape_footer.tagCount),
733 ape2long(ape_footer.flags),
734 is_id3v1 (fp), is_id3v2 (fp), is_ape (fp), is_ape_ver (fp));
735
736 apeTag2 = ape2long(ape_footer.version);
737 buffLength = is_ape(fp) + ID3V1_TAG_SIZE;
738 buff = (unsigned char *) malloc(buffLength);
739 if (buff == NULL) {
740 PRINT_ERR( "ERROR->libapetag->apetag_read_fp:malloc\n");
741 return ATL_MALOC;
742 }
743
744 fseek (fp, id3v1 ? -ape2long (ape_footer.length) -
745 ID3V1_TAG_SIZE : -ape2long (ape_footer.length), SEEK_END);
746 memset(buff, 0, buffLength);
747 if (ape2long(ape_footer.length) != fread(buff, 1, ape2long(ape_footer.length), fp)) {
748 PRINT_ERR( "ERROR->libapetag->apetag_read_fp:fread2\n");
749 fseek(fp, savedFilePosition, SEEK_SET);
750 free(buff);
751 return ATL_FREAD;
752 }
753
754 tagCount = ape2long(ape_footer.tagCount);
755
756 end = buff + ape2long(ape_footer.length) - sizeof (ape_footer);
757
758 for (p = buff; p < end && tagCount--;) {
759 /* 8 = sizeof( sizeValue+flags ) */
760 unsigned long flags = ape2long (p + 4);
761 unsigned long sizeValue = ape2long(p);
762 unsigned long sizeName;
763 char *name = (char *)p + 8;
764 char *value;
765
766 sizeName = strlen((char *)p + 8);
767 value = (char *)p + sizeName + 8 + 1;
768 if (apeTag2 == 1000 && value[sizeValue - 1] == '\0') {
769 libapetag_maloc_cont(mem_cnt, flags,
770 sizeName, name,
771 sizeValue - 1, value);
772 } else {
773 libapetag_maloc_cont(mem_cnt, flags,
774 sizeName, name,
775 sizeValue, value);
776 }
777 p += (sizeName + sizeValue + 8 + 1);
778 }
779
780 free(buff);
781 } else { /* if no ape tag */
782 PRINT_D5(">apetaglib>READ_FP>>%s: v1=%i v2=%i ape=%i[v%i]\n",
783 filename, is_id3v1 (fp), is_id3v2 (fp), is_ape (fp), is_ape_ver (fp));
784 }
785
786 #ifdef ID3V2_READ
787 if (!(flag & DONT_READ_TAG_ID3V2) && filename!=NULL && is_id3v2(fp)!=0) {
788 readtag_id3v2(mem_cnt, filename);
789 }
790 #endif
791 if (!(flag & DONT_READ_TAG_ID3V1) && (id3v1)) {
792 readtag_id3v1_fp(mem_cnt, fp);
793 }
794
795 fseek(fp, savedFilePosition, SEEK_SET);
796 return 0;
797 }
798
799 /*
800 PL: wraper na apetag_read_fp
801 PL: otwiera plik wczytuje co trzeba i zamyka
802 PL: dobre do wczytywania informacji ktore sa potrzebne pozniej bez fatygi otwierania pliku
803 */
804 /**
805 \brief read file and add frames
806
807 \param mem_cnt object #apetag
808 \param filename file name
809 \param flag
810 \return 0 - OK else check #atl_return
811 */
812 int
apetag_read(apetag * mem_cnt,const char * filename,int flag)813 apetag_read (apetag *mem_cnt, const char *filename, int flag)
814 {
815 FILE *fp;
816
817 if (mem_cnt==NULL) {
818 PRINT_ERR(">apetaglib>READ>FATAL>apetag_init()\n");
819 return ATL_NOINIT;
820 }
821
822 fp = g_fopen (filename, "rb");
823 if (fp == NULL)
824 return ATL_FOPEN;
825
826 apetag_read_fp (mem_cnt, fp, filename,flag);
827
828 fclose (fp);
829
830 return 0;
831 }
832
833 /*
834 PL: Funkcja dla qsorta ze specjalnymi wyjatkami
835 PL: uzywana w apetag_save
836 :NON_USER:!!!
837 */
838 static int
libapetag_qsort(struct tag ** a,struct tag ** b)839 libapetag_qsort (struct tag **a, struct tag **b)
840 {
841 const char * const sorting[] = { "Artist", "Year", "Album", "Track", "Title", "Genre", NULL, NULL };
842 int n, m;
843
844 if (!a || !b || !*a || !*b) {
845 PRINT_ERR ("ERROR->libapetag->apetag_qsort:*a ||*b = NULL : FATAL PLEASE REPORT!!!\n");
846 return 0;
847 }
848 for (n = 0; sorting[n] != NULL; n++) {
849 if (strcasecmp ((*a)->name, sorting[n]) == 0)
850 break;
851 }
852 if (sorting[n] == NULL)
853 n += (*a)->sizeValue + 1; /* n = max entries of sorting + size of tag */
854
855 for (m = 0; sorting[m] != NULL; m++) {
856 if (strcasecmp ((*b)->name, sorting[m]) == 0)
857 break;
858 }
859 if (sorting[m] == NULL)
860 m += (*b)->sizeValue + 1; /* m = max entries */
861
862 if (n == m)
863 return 0;
864 if (n > m)
865 return 1;
866 else
867 return -1;
868 }
869
870 /*
871 PL: domyslne %flag% = APE_TAG_V2 + SAVE_NEW_OLD_APE_TAG
872 */
873 /**
874 \brief save apetag to file
875
876 \param filename file name
877 \param mem_cnt object #apetag
878 \param flag flags for read/save
879 \return 0 - OK else check #atl_return
880 \warning for ape tag v 1 you must add frames in iso-1
881 for v 2 this must be in utf-8
882 \todo PL: v9 sprawdzac flagi w footer i na tej podstawie zmieniac skipBytes
883 bez domniemywania ze v2 ma zawsze oba
884
885 */
886 int
apetag_save(const char * filename,apetag * mem_cnt,int flag)887 apetag_save (const char *filename, apetag *mem_cnt, int flag)
888 {
889 FILE *fp;
890 struct _id3v1Tag id3v1_tag;
891 int id3v1;
892 int apeTag, saveApe2;
893 int tagCount = 0;
894 int realCountTag = 0;
895 struct _apetag_footer ape_footer;
896 long skipBytes;
897 unsigned char *buff, *p;
898 struct tag **mTag;
899 size_t tagSSize = 32;
900 int n;
901 unsigned char temp[4];
902
903 if (mem_cnt==NULL) {
904 PRINT_ERR("ERROR->apetaglib>apetag_save::apetag_init()\n");
905 return ATL_NOINIT;
906 }
907
908 fp = g_fopen (filename, "rb+");
909 if (fp == NULL) {
910 PRINT_ERR ( "ERROR->apetaglib->apetag_save::fopen (r+)\n");
911 return ATL_FOPEN;
912 }
913
914 skipBytes = 0;
915 id3v1 = is_id3v1 (fp);
916 apeTag = is_ape (fp);
917 saveApe2 = !(flag & APE_TAG_V1); // (flag & APE_TAG_V2) ? 1 : (flag & APE_TAG_V1);
918
919 if (id3v1) {
920 fseek (fp, -ID3V1_TAG_SIZE, SEEK_END);
921 if (fread (&id3v1_tag, 1, sizeof (struct _id3v1Tag), fp)
922 != sizeof (struct _id3v1Tag))
923 {
924 PRINT_ERR ("ERROR->apetaglib->apetag_save::fread");
925 fclose (fp);
926 return ATL_FREAD;
927 }
928 skipBytes += id3v1;
929 }
930 skipBytes += apeTag;
931
932 if (!(flag & SAVE_NEW_APE_TAG)) {
933 apetag_read_fp (mem_cnt, fp, filename, flag);
934 }
935
936 mTag = (mem_cnt->tag);
937 qsort( mTag , mem_cnt->countTag , sizeof(struct tag *),
938 (int (*)(const void *,const void *))libapetag_qsort);
939
940 for (n = 0; (mem_cnt->countTag) > n; n++) {
941 if (mTag[n]->sizeValue != 0) {
942 tagSSize += ((long) mTag[n]->sizeName + (long) mTag[n]->sizeValue);
943 tagSSize += 4 + 4 + 1 + (saveApe2 ? 0 : 1); // flag & sizeValue & \0
944 realCountTag++; // count not deleted tag (exl. not real)
945 }
946 }
947 if (!!(flag & SAVE_CREATE_ID3V1_TAG )) {
948 make_id3v1_tag(mem_cnt, &id3v1_tag);
949 tagSSize += ID3V1_TAG_SIZE;
950 }
951 //PRINT_D4 (">apetaglib>SAVE>>: size %li %i %i %i\n", tagSSize,
952 // mem_cnt->countTag, flag, saveApe2);
953 buff = (unsigned char *) malloc (tagSSize + (saveApe2 ? 32 : 0));
954 p = buff;
955
956 if (buff == NULL) {
957 PRINT_ERR ("ERROR->libapetag->apetag_save::malloc");
958 return ATL_MALOC;
959 }
960 memset (ape_footer.id, 0, sizeof (ape_footer));
961 memcpy (ape_footer.id, "APETAGEX", sizeof (ape_footer.id));
962 long2ape (ape_footer.flags, 0l);
963 if (!!(flag & SAVE_CREATE_ID3V1_TAG ))
964 long2ape (ape_footer.length, tagSSize - ID3V1_TAG_SIZE);
965 else
966 long2ape (ape_footer.length, tagSSize);
967 //long2ape(ape_footer.tagCount, mem_cnt->countTag);
968 long2ape(ape_footer.tagCount, realCountTag);
969 long2ape (ape_footer.version, (saveApe2 ? 2000 : 1000));
970 if (saveApe2) {
971 long2ape (ape_footer.flags, HEADER_THIS_IS + HEADER_IS + FOOTER_IS);
972 memcpy (p, ape_footer.id, sizeof (ape_footer));
973 p += sizeof (ape_footer);
974 }
975
976 mTag = (mem_cnt->tag);
977 for (n = 0; (mem_cnt->countTag) > n; n++) {
978 if (saveApe2) {
979 long2ape (temp, mTag[n]->sizeValue);
980 } else {
981 /* TODO:convert UTF8 to ASCII mTag[n]->value */
982 long2ape (temp, (mTag[n]->sizeValue) + 1);
983 }
984
985 if (mTag[n]->sizeValue != 0) {
986 memcpy (p, temp, 4);
987 p += 4;
988 long2ape (temp, (saveApe2!=0) ? mTag[n]->flags : 0l );
989 memcpy (p, temp, 4);
990 p += 4;
991
992 memcpy (p, mTag[n]->name, mTag[n]->sizeName);
993 p += mTag[n]->sizeName;
994 memcpy (p, "\0", 1);
995 p++;
996 memcpy (p, mTag[n]->value, mTag[n]->sizeValue);
997 p += mTag[n]->sizeValue;
998
999 if (!saveApe2) {
1000 memcpy (p, "\0", 1);
1001 p++;
1002 }
1003 tagCount++;
1004 }
1005 } /* for */
1006
1007 if (saveApe2)
1008 long2ape (ape_footer.flags, FOOTER_THIS_IS + FOOTER_IS + HEADER_IS);
1009
1010 memcpy (p, ape_footer.id, sizeof (ape_footer));
1011 p += sizeof (ape_footer);
1012
1013 if (!!(flag & SAVE_CREATE_ID3V1_TAG )) {
1014 memcpy (p, &id3v1_tag , sizeof (struct _id3v1Tag));
1015 }
1016
1017 /* write tag to file and truncate */
1018 if (!(flag & SAVE_FAKE_SAVE)) {
1019 size_t fileSize;
1020 size_t newFileSize;
1021 size_t writedBytes;
1022 int fd;
1023
1024 fseek (fp, 0, SEEK_END);
1025 fileSize = ftell (fp);
1026 fseek (fp, fileSize - skipBytes, SEEK_SET);
1027 if (tagCount != 0) {
1028 newFileSize = (fileSize - skipBytes + tagSSize + (saveApe2 ? 32 : 0));
1029 writedBytes = fwrite (buff, 1, tagSSize + (saveApe2 ? 32 : 0), fp);
1030 if (writedBytes != tagSSize + (saveApe2 ? 32 : 0)) {
1031 PRINT_ERR ("FATAL_ERROR->libapetag->apetag_save::fwrite [data lost]");
1032 fclose (fp);
1033 free (buff);
1034 return ATL_FWRITE;
1035 }
1036 fseek (fp, newFileSize, SEEK_SET);
1037 PRINT_D4 (">apetaglib>SAVE>> write:%zu == tag:%zu file: %zu->%zu\n",
1038 writedBytes, tagSSize + (saveApe2 ? 32 : 0), fileSize, newFileSize);
1039 } else {
1040 newFileSize = (fileSize - skipBytes);
1041 }
1042 fflush (fp);
1043
1044 if ((fd = fileno (fp)) == -1)
1045 {
1046 PRINT_ERR ("FATAL_ERROR->libapetag->apetag_save::fileno [file not truncated]");
1047 fclose (fp);
1048 return ATL_FWRITE;
1049 }
1050
1051 #ifdef G_OS_WIN32
1052 if (_chsize (fd, newFileSize) == -1)
1053 #else
1054 if (ftruncate (fd, newFileSize) == -1)
1055 #endif
1056 {
1057 PRINT_ERR ("FATAL_ERROR->libapetag->apetag_save::fwrite [file not truncated]");
1058 }
1059
1060 fclose (fp);
1061 } else { /* !!SAVE_FAKE_SAVE */
1062 libapetag_print_mem_cnt (mem_cnt);
1063 }
1064 free (buff);
1065
1066 return 0;
1067 }
1068