1 /*
2 This file is part of Deadbeef Player source code
3 http://deadbeef.sourceforge.net
4
5 library for reading tags from various audio files
6
7 Copyright (C) 2009-2016 Alexey Yakovenko
8
9 This software is provided 'as-is', without any express or implied
10 warranty. In no event will the authors be held liable for any damages
11 arising from the use of this software.
12
13 Permission is granted to anyone to use this software for any purpose,
14 including commercial applications, and to alter it and redistribute it
15 freely, subject to the following restrictions:
16
17 1. The origin of this software must not be misrepresented; you must not
18 claim that you wrote the original software. If you use this software
19 in a product, an acknowledgment in the product documentation would be
20 appreciated but is not required.
21 2. Altered source versions must be plainly marked as such, and must not be
22 misrepresented as being the original software.
23 3. This notice may not be removed or altered from any source distribution.
24
25 Alexey Yakovenko waker@users.sourceforge.net
26 */
27 #ifdef HAVE_CONFIG_H
28 #include "config.h"
29 #endif
30 #include "junklib.h"
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #undef HAVE_ICI
35 #if HAVE_ICONV
36 #include <iconv.h>
37 #elif HAVE_ICU
38 #warning icu
39 #include <unicode/utypes.h>
40 #include <unicode/ucnv.h>
41 #else
42 #define DDB_RECODE
43 #include "ConvertUTF/ConvertUTF.h"
44 uint16_t sj_to_unicode[] = {
45 #include "sj_to_unicode.h"
46 };
47 #endif
48 #include <limits.h>
49 #include <errno.h>
50 #include <ctype.h>
51 #include <unistd.h>
52 #include <assert.h>
53 #include <fcntl.h>
54 #ifndef __linux__
55 #define O_LARGEFILE 0
56 #endif
57 #include <sys/stat.h>
58 #include "playlist.h"
59 #include "utf8.h"
60 #include "plugins.h"
61 #include "conf.h"
62
63 int enable_cp1251_detection = 1;
64 int enable_cp936_detection = 0;
65 int enable_shift_jis_detection = 0;
66
67 #define MAX_TEXT_FRAME_SIZE 10000
68 #define MAX_CUESHEET_FRAME_SIZE 10000
69 #define MAX_APEV2_FRAME_SIZE 2000000
70 #define MAX_ID3V2_FRAME_SIZE 100000
71 #define MAX_ID3V2_APIC_FRAME_SIZE 2000000
72
73 #define UTF8_STR "utf-8"
74
75 //#define trace(...) { fprintf(stderr, __VA_ARGS__); }
76 #define trace(fmt,...)
77
78 #define min(x,y) ((x)<(y)?(x):(y))
79 #define max(x,y) ((x)>(y)?(x):(y))
80
81
82 // mapping between ddb metadata names and id3v2/apev2 names
83 #define FRAME_MAPPINGS 5
84 enum {
85 MAP_DDB = 0,
86 MAP_ID3V23 = 1,
87 MAP_ID3V24 = 2,
88 MAP_ID3V22 = 3,
89 MAP_APEV2 = 4
90 };
91
92 // map of known id3v2 and apev2 text tags
93 // order: ddb, id3-2.3, 2.4, 2.2, apev2
94 static const char *frame_mapping[] = {
95 // these tags will be displayed and edited uniformly for all tag types
96 "artist", "TPE1", "TPE1", "TP1", "Artist",
97 "disc", "TPOS", "TPOS", "TPA", "Disc", // NOTE: this is special case when writing id3v2
98 "title", "TIT2", "TIT2", "TT2", "Title",
99 "album", "TALB", "TALB", "TAL", "Album",
100 "copyright", "TCOP", "TCOP", "TCO", "Copyright",
101 "genre", "TCON", "TCON", "TCO", "Genre",
102 "composer", "TCOM", "TCOM", "TCM", "Composer",
103 "year", "TYER", "TDRC", "TYE", "Year", // NOTE: TDRC and TYER are slightly different, and are converted on read/write
104 "track", "TRCK", "TRCK", "TRK", "Track", // NOTE: this is special case when writing id3v2
105 // misc id3v2 fields
106 // these might or might not have appropriate fields in every tag type
107 "BAND", "TPE2", "TPE2", "TP2", NULL,
108 "ENCODER", "TENC", "TENC", "TEN", NULL,
109 "BEATS_PER_MINUTE", "TBPM", "TBPM", "TBP", NULL,
110 "PLAYLIST_DELAY", "TDLY", "TDLY", "TDY", NULL,
111 "TEXT_WRITERS", "TEXT", "TEXT", "TXT", NULL,
112 "FILE_TYPE", "TFLT", "TFLT", "TFT", NULL,
113 "CONTENT_GROUP_DESCRIPTION", "TIT1", "TIT1", "TT1", NULL,
114 "SUBTITLE", "TIT3", "TIT3", "TT3", NULL,
115 "INITIAL_KEY", "TKEY", "TKEY", "TKE", NULL,
116 "LANGUAGES", "TLAN", "TLAN", "TLA", NULL,
117 "LENGTH", "TLEN", "TLEN", "TLE", NULL,
118 "MEDIA_TYPE", "TMED", "TMED", "TMT", NULL,
119 "ORIGINAL_ALBUM_TITLE", "TOAL", "TOAL", "TOT", NULL,
120 "ORIGINAL_FILENAME", "TOFN", "TOFN", "TOF", NULL,
121 "ORIGINAL_TEXT_WRITERS", "TOLY", "TOLY", "TOL", NULL,
122 "ORIGINAL_ARTISTS", "TOPE", "TOPE", "TOA", NULL,
123 "FILE_OWNER", "TOWN", "TOWN", NULL, NULL,
124 "PERFORMER_REFINEMENT", "TPE3", "TPE3", "TP3", NULL,
125 "MODIFIED_BY", "TPE4", "TPE4", "TP4", NULL,
126 "PUBLISHER", "TPUB", "TPUB", "TPB", NULL,
127 "INTERNET_RADIO_STATION_NAME", "TRSN", "TRSN", NULL, NULL,
128 "INTERNET_RADIO_STATION_OWNER", "TRSO", "TRSO", NULL, NULL,
129 "ISRC", "TSRC", "TSRC", NULL, NULL,
130 "ENCODING_SOFTWARE_HARDWARE", "TSSE", "TSSE", "TSS", NULL,
131 "RECORDING_TIME", NULL, "TDRC", NULL, NULL,
132 "RELEASE_TIME", NULL, "TDRL", NULL, NULL,
133 "TAGGING_TIME", NULL, "TDTG", NULL, NULL,
134 "ALBUM_SORT_ORDER", NULL, "TSOA", NULL, NULL,
135 "PERFORMER_SORT_ORDER", NULL, "TSOP", NULL, NULL,
136 "TITLE_SORT_ORDER", NULL, "TSOT", NULL, NULL,
137 "SIZE", "TSIZ", NULL, "TSI", NULL,
138 "RECORDING_DATES", "TRDA", NULL, "TRD", NULL,
139 "INVOLVED_PEOPLE_LIST", NULL, "TIPL", NULL, NULL,
140 "MUSICIAN_CREDITS_LIST", NULL, "TMCL", NULL, NULL,
141 "ENCODING_TIME", NULL, "TDEN", NULL, NULL,
142 "ORIGINAL_RELEASE_TIME", NULL, "TDOR", NULL, NULL,
143 "ORIGINAL_RELEASE_YEAR", NULL, NULL, NULL, "ORIGINALYEAR",
144 "MOOD", NULL, "TMOO", NULL, NULL,
145 "PRODUCED_NOTICE", NULL, "TPRO", NULL, NULL,
146 "musicbrainz_trackid", NULL, NULL, NULL, NULL,
147 NULL
148 };
149
150 // replaygain key names in both id3v2.3+ TXX and APEv2
151 static const char *tag_rg_names[] = {
152 "replaygain_album_gain",
153 "replaygain_album_peak",
154 "replaygain_track_gain",
155 "replaygain_track_peak",
156 NULL
157 };
158
159 // replaygain key names in deadbeef internal metadata
160 const char *ddb_internal_rg_keys[] = {
161 ":REPLAYGAIN_ALBUMGAIN",
162 ":REPLAYGAIN_ALBUMPEAK",
163 ":REPLAYGAIN_TRACKGAIN",
164 ":REPLAYGAIN_TRACKPEAK",
165 NULL
166 };
167
168 static uint32_t
extract_i32(const uint8_t * buf)169 extract_i32 (const uint8_t *buf)
170 {
171 uint32_t x;
172 // big endian extract
173
174 x = buf[0];
175 x <<= 8;
176 x |= buf[1];
177 x <<= 8;
178 x |= buf[2];
179 x <<= 8;
180 x |= buf[3];
181
182 return x;
183 }
184
185 static inline uint32_t
extract_i32_le(unsigned char * buf)186 extract_i32_le (unsigned char *buf)
187 {
188 uint32_t x;
189 // little endian extract
190
191 x = buf[3];
192 x <<= 8;
193 x |= buf[2];
194 x <<= 8;
195 x |= buf[1];
196 x <<= 8;
197 x |= buf[0];
198
199 return x;
200 }
201
202 static inline uint16_t
extract_i16(const uint8_t * buf)203 extract_i16 (const uint8_t *buf)
204 {
205 uint16_t x;
206 // big endian extract
207
208 x = buf[0];
209 x <<= 8;
210 x |= buf[1];
211
212 return x;
213 }
214
215 static inline float
extract_f32(unsigned char * buf)216 extract_f32 (unsigned char *buf) {
217 float f;
218 uint32_t *x = (uint32_t *)&f;
219 *x = buf[0];
220 *x <<= 8;
221 *x |= buf[1];
222 *x <<= 8;
223 *x |= buf[2];
224 *x <<= 8;
225 *x |= buf[3];
226 return f;
227 }
228
229 #ifdef DDB_RECODE
230
231 static int
cp1251_to_utf8(const uint8_t * in,int inlen,uint8_t * out,int outlen)232 cp1251_to_utf8(const uint8_t *in, int inlen, uint8_t *out, int outlen) {
233 static const long utf[256] = {
234 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,
235 31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,
236 59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,
237 87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,
238 111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,1026,1027,8218,
239 1107,8222,8230,8224,8225,8364,8240,1033,8249,1034,1036,1035,1039,1106,8216,8217,
240 8220,8221,8226,8211,8212,8250,8482,1113,8250,1114,1116,1115,1119,160,1038,1118,1032,
241 164,1168,166,167,1025,169,1028,171,172,173,174,1031,176,177,1030,1110,1169,181,182,
242 183,1105,8470,1108,187,1112,1029,1109,1111,1040,1041,1042,1043,1044,1045,1046,1047,
243 1048,1049,1050,1051,1052,1053,1054,1055,1056,1057,1058,1059,1060,1061,1062,1063,
244 1064,1065,1066,1067,1068,1069,1070,1071,1072,1073,1074,1075,1076,1077,1078,1079,
245 1080,1081,1082,1083,1084,1085,1086,1087,1088,1089,1090,1091,1092,1093,1094,1095,
246 1096,1097,1098,1099,1100,1101,1102,1103
247 };
248
249 uint8_t *out_start = out;
250 uint8_t *end = out + outlen;
251
252 for(int i = 0; i < inlen && out < end - 4; i++) {
253 long c = utf[*in++];
254 if (c < 0x80) {
255 *out++ = c;
256 }
257 else if (c < 0x800) {
258 *out++ = (c >> 6) | 0xc0;
259 *out++ = (c & 0x3f) | 0x80;
260 }
261 else if( c < 0x10000 ) {
262 *out++ = (c >> 12) | 0xe0;
263 *out++ = ((c >> 6) & 0x3f) | 0x80;
264 *out++ = (c & 0x3f) | 0x80;
265 }
266 }
267 *out++ = 0;
268 return (int)(out - out_start);
269 }
270
271 int
junk_cp1252_to_utf8(const uint8_t * in,int inlen,uint8_t * out,int outlen)272 junk_cp1252_to_utf8(const uint8_t *in, int inlen, uint8_t *out, int outlen) {
273 int len = 0;
274 while (inlen > 0 && outlen-len > 2) {
275 uint8_t c=*in;
276
277 switch (c) {
278 case 192 ... 255:
279 *out++ = 195;
280 *out++ = c - 64;
281 len += 2;
282 break;
283 case 160 ... 191:
284 *out++ = 0xc2;
285 *out++ = c;
286 len += 2;
287 break;
288 #define CONV2(x,y,z) case x:\
289 *out++ = y;\
290 *out++ = z;\
291 len += 2;\
292 break;
293 #define CONV3(x,y,z,w) case x:\
294 *out++ = y;\
295 *out++ = z;\
296 *out++ = w;\
297 len += 3;\
298 break;
299 CONV2(0x9f,0xc5,0xb8);
300 CONV2(0x9e,0xc5,0xbe);
301 CONV3(0x9d,0xef,0xbf,0xbd);
302 CONV3(0x80,0xe2,0x82,0xac);
303 CONV3(0x81,0xef,0xbf,0xbd);
304 CONV3(0x82,0xe2,0x80,0x9a);
305 CONV2(0x83,0xc6,0x92);
306 CONV3(0x84,0xe2,0x80,0x9e);
307 CONV3(0x85,0xe2,0x80,0xa6);
308 CONV3(0x86,0xe2,0x80,0xa0);
309 CONV3(0x87,0xe2,0x80,0xa1);
310 CONV2(0x88,0xcb,0x86);
311 CONV3(0x89,0xe2,0x80,0xb0);
312 CONV2(0x8a,0xc5,0xa0);
313 CONV3(0x8b,0xe2,0x80,0xb9);
314 CONV2(0x8c,0xc5,0x92);
315 CONV3(0x8d,0xef,0xbf,0xbd);
316 CONV2(0x8e,0xc5,0xbd);
317 CONV3(0x8f,0xef,0xbf,0xbd);
318 CONV3(0x90,0xef,0xbf,0xbd);
319 CONV3(0x91,0xe2,0x80,0x98);
320 CONV3(0x92,0xe2,0x80,0x99);
321 CONV3(0x93,0xe2,0x80,0x9c);
322 CONV3(0x94,0xe2,0x80,0x9d);
323 CONV3(0x95,0xe2,0x80,0xa2);
324 CONV3(0x96,0xe2,0x80,0x93);
325 CONV3(0x97,0xe2,0x80,0x94);
326 CONV2(0x98,0xcb,0x9c);
327 CONV3(0x99,0xe2,0x84,0xa2);
328 CONV2(0x9a,0xc5,0xa1);
329 CONV3(0x9b,0xe2,0x80,0xba);
330 CONV2(0x9c,0xc5,0x93);
331 #undef CONV2
332 #undef CONV3
333 default:
334 if (c >= 127) {
335 trace ("iso8859 char: %d\n", c);
336 }
337 *out++ = c;
338 len++;
339 break;
340 }
341
342 in++;
343 inlen--;
344 }
345 *out = 0;
346 return len;
347 }
348
349 int
junk_utf8_to_cp1252(const uint8_t * in,int inlen,uint8_t * out,int outlen)350 junk_utf8_to_cp1252(const uint8_t *in, int inlen, uint8_t *out, int outlen) {
351 uint8_t *outptr = out;
352 const char *cp1252_charset[] = {"€", "", "‚", "ƒ", "„", "…", "†", "‡", "ˆ", "‰", "Š", "‹", "Œ", "", "Ž", "", "", "‘", "’", "“", "”", "•", "–", "—", "˜", "™", "š", "›", "œ", "", "ž", "Ÿ", " ", "¡", "¢", "£", "¤", "¥", "¦", "§", "¨", "©", "ª", "«", "¬", "", "®", "¯", "°", "±", "²", "³", "´", "µ", "¶", "·", "¸", "¹", "º", "»", "¼", "½", "¾", "¿", "À", "Á", "Â", "Ã", "Ä", "Å", "Æ", "Ç", "È", "É", "Ê", "Ë", "Ì", "Í", "Î", "Ï", "Ð", "Ñ", "Ò", "Ó", "Ô", "Õ", "Ö", "×", "Ø", "Ù", "Ú", "Û", "Ü", "Ý", "Þ", "ß", "à", "á", "â", "ã", "ä", "å", "æ", "ç", "è", "é", "ê", "ë", "ì", "í", "î", "ï", "ð", "ñ", "ò", "ó", "ô", "õ", "ö", "÷", "ø", "ù", "ú", "û", "ü", "ý", "þ", "ÿ", NULL};
353 while (inlen && outlen > 0) {
354 if (*in < 0x80) {
355 *out++ = *in++;
356 outlen--;
357 inlen--;
358 }
359 else {
360 int idx = 0;
361 u8_inc((char *)in, &idx);
362 int i;
363 for (i = 0; cp1252_charset[i]; i++) {
364 if (strlen (cp1252_charset[i]) == idx && !memcmp (in, cp1252_charset[i], idx)) {
365 *out++ = i + 0x80;
366 outlen--;
367 break;
368 }
369 }
370 if (!cp1252_charset[i]) {
371 return -1;
372 }
373 in += idx;
374 inlen -= idx;
375 }
376 }
377 *out = 0;
378 return (int)(out-outptr);
379 }
380
381 int
junk_utf8_to_ascii(const uint8_t * in,int inlen,uint8_t * out,int outlen)382 junk_utf8_to_ascii(const uint8_t *in, int inlen, uint8_t *out, int outlen) {
383 uint8_t *outptr = out;
384 while (inlen && outlen > 0) {
385 if (*in < 0x80) {
386 *out++ = *in++;
387 outlen--;
388 inlen--;
389 }
390 else {
391 int idx = 0;
392 u8_inc((char *)in, &idx);
393 in += idx;
394 inlen -= idx;
395 }
396 }
397 *out = 0;
398 return (int)(out-outptr);
399 }
400
401 ConversionResult
ConvertUTF16BEtoUTF8(const UTF16 ** sourceStart,const UTF16 * sourceEnd,UTF8 ** targetStart,UTF8 * targetEnd,ConversionFlags flags)402 ConvertUTF16BEtoUTF8 (const UTF16** sourceStart, const UTF16* sourceEnd, UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags) {
403 // swap to make it little endian
404 size_t sourceLESize = (size_t)(sourceEnd - *sourceStart) * sizeof (UTF16);
405 UTF16 sourceLE[sourceLESize];
406 UTF16 *pLE = sourceLE;
407 for (const UTF16 *p = *sourceStart; p != sourceEnd; p++) {
408 *pLE++ = extract_i16((const uint8_t *)p);
409 }
410 const UTF16 *leStart = sourceLE;
411 ConversionResult res = ConvertUTF16toUTF8(&leStart, pLE, targetStart, targetEnd, flags);
412 *sourceStart += pLE - sourceLE;
413 return res;
414 }
415
416 ConversionResult
ConvertUTF8toUTF16BE(const UTF8 ** sourceStart,const UTF8 * sourceEnd,UTF16 ** targetStart,UTF16 * targetEnd,ConversionFlags flags)417 ConvertUTF8toUTF16BE (const UTF8** sourceStart, const UTF8* sourceEnd, UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags) {
418 UTF16 *output = *targetStart;
419 ConversionResult res = ConvertUTF8toUTF16(sourceStart, sourceEnd, targetStart, targetEnd, flags);
420 if (res == conversionOK) {
421 for (UTF16 *p = output; p != *targetStart; p++) {
422 *p = extract_i16((const uint8_t *)p);
423 }
424 }
425 return res;
426 }
427
ddb_iconv(const char * cs_out,const char * cs_in,char * out,int outlen,const char * in,int inlen)428 int ddb_iconv (const char *cs_out, const char *cs_in, char *out, int outlen, const char *in, int inlen) {
429 int len = -1;
430 *out = 0;
431 if (inlen==0) {
432 return 0;
433 }
434
435
436 if (!strcmp (cs_in, "UTF-16")) {
437 if (in[0] == 0xfe && in[1] == 0xff) {
438 cs_in = "UTF-16BE";
439 }
440 else {
441 cs_in = "UTF-16LE";
442 }
443 }
444
445 // to utf8 branch
446 if (!strcasecmp (cs_out, UTF8_STR)) {
447 if (!strcasecmp (cs_in, UTF8_STR)) {
448 memcpy (out, in, inlen);
449 out[inlen] = 0;
450 int valid = u8_valid (out, inlen, NULL);
451 if (valid) {
452 len = inlen;
453 }
454 }
455 else if (!strcasecmp (cs_in, "cp1251")) {
456 len = cp1251_to_utf8 (in, inlen, out, outlen);
457 }
458 else if (!strcasecmp (cs_in, "iso8859-1") || !strcasecmp (cs_in, "cp1252")) {
459 len = junk_cp1252_to_utf8 (in, inlen, out, outlen);
460 }
461 else if (!strcasecmp (cs_in, "UTF-16LE") || !strcasecmp (cs_in, "UCS-2LE")) {
462 char *target = out;
463 ConversionResult result = ConvertUTF16toUTF8 ((const UTF16**)&in, (const UTF16*)(in + inlen), (UTF8**)&target, (UTF8*)(out + outlen), strictConversion);
464 if (result == conversionOK) {
465 *target = 0;
466 len = target - out;
467 }
468 }
469 else if (!strcasecmp (cs_in, "UTF-16BE") || !strcasecmp (cs_in, "UCS-2BE")) {
470 // convert to big endian
471 char temp[inlen];
472 for (int i = 0; i < inlen; i += 2) {
473 temp[i] = in[i+1];
474 temp[i+1] = in[i];
475 }
476 char *target = out;
477 char *src = temp;
478 ConversionResult result = ConvertUTF16BEtoUTF8 ((const UTF16**)&src, (const UTF16*)(temp + inlen), (UTF8**)&target, (UTF8*)(out + outlen), strictConversion);
479 if (result == conversionOK) {
480 *target = 0;
481 len = target - out;
482 }
483 }
484 else if (!strcasecmp (cs_in, "SHIFT-JIS")) {
485 int len = 0;
486 while (inlen > 0 && len < outlen) {
487 if (*in > 0) {
488 *out++ = *in++;
489 inlen--;
490 len++;
491 }
492 else if (inlen < 2) {
493 return -1;
494 }
495 else {
496 // find character in table
497 uint16_t c = (((uint8_t*)in)[0] << 8) | ((uint8_t*)in)[1];
498 int i;
499 for (i = 0; sj_to_unicode[i]; i += 2) {
500 if (c == sj_to_unicode[i]) {
501 break;
502 }
503 }
504 if (sj_to_unicode[i]) {
505 // slow conversion!
506 char unicode_val[2] = { (sj_to_unicode[i+1] & 0xff00) >> 8, sj_to_unicode[i+1] & 0xff };
507 char utf8_val[5];
508 char *src = unicode_val, *dst = utf8_val;
509
510 ConversionResult res = ConvertUTF16toUTF8 ((const UTF16**)&src, (const UTF16 *)(src+2), (UTF8**)&dst, dst+5, strictConversion);
511 if (res == conversionOK) {
512 if (src - utf8_val < outlen-len) {
513 memcpy (out, utf8_val, src - utf8_val);
514 out += src - utf8_val;
515 len += src - utf8_val;
516 inlen -= 2;
517 in += 2;
518 }
519 else {
520 return -1;
521 }
522 }
523 else {
524 return -1;
525 }
526 }
527 else {
528 return -1; // error
529 }
530 }
531 }
532 }
533 else {
534 fprintf (stderr, "invalid conversion request: %s -> %s\n", cs_in, cs_out);
535 }
536 }
537 else if (!strcasecmp (cs_in, UTF8_STR)) {
538 if (!strcasecmp (cs_out, "UTF-16LE") || !strcasecmp (cs_out, "UCS-2LE")) {
539 char *target = out;
540 ConversionResult result = ConvertUTF8toUTF16 ((const UTF8**)&in, (const UTF8*)(in + inlen), (UTF16**)&target, (UTF16*)(out + outlen), strictConversion);
541 if (result == conversionOK) {
542 *target = 0;
543 *(target+1) = 0;
544 len = target - out;
545 }
546 }
547 else if (!strcasecmp (cs_out, "UTF-16BE") || !strcasecmp (cs_out, "UCS-2BE")) {
548 char *target = out;
549 ConversionResult result = ConvertUTF8toUTF16BE ((const UTF8**)&in, (const UTF8*)(in + inlen), (UTF16**)&target, (UTF16*)(out + outlen), strictConversion);
550 if (result == conversionOK) {
551 *target = 0;
552 *(target+1) = 0;
553 len = target - out;
554 }
555 }
556 else if (!strcasecmp (cs_out, "cp1252") || !strcasecmp (cs_out, "iso8859-1")) {
557 int res = junk_utf8_to_cp1252((uint8_t *)in, inlen, (uint8_t *)out, outlen);
558 if (res >= 0) {
559 len = res;
560 }
561 }
562 else if (!strcasecmp (cs_out, "ascii")) {
563 int res = junk_utf8_to_ascii((uint8_t *)in, inlen, (uint8_t *)out, outlen);
564 if (res >= 0) {
565 len = res;
566 }
567 }
568 else {
569 fprintf (stderr, "invalid conversion request: %s -> %s\n", cs_in, cs_out);
570 }
571 }
572 else {
573 fprintf (stderr, "invalid conversion request: %s -> %s\n", cs_in, cs_out);
574 }
575 trace ("\033[0;31mddb_iconv: %s -> %s, in: %s, out: %s\033[37;0m\n", cs_in, cs_out, in, out);
576 return len;
577 }
578 #endif
579
580 int
junk_iconv(const char * in,int inlen,char * out,int outlen,const char * cs_in,const char * cs_out)581 junk_iconv (const char *in, int inlen, char *out, int outlen, const char *cs_in, const char *cs_out) {
582 // NOTE: this function must support utf8->utf8 conversion, used for validation
583 #if HAVE_ICONV
584 iconv_t cd = iconv_open (cs_out, cs_in);
585 if (cd == (iconv_t)-1) {
586 return -1;
587 }
588 #ifdef __linux__
589 char *pin = (char*)in;
590 #else
591 const char *pin = in;
592 #endif
593
594 size_t inbytesleft = inlen;
595 size_t outbytesleft = outlen;
596
597 char *pout = out;
598
599 size_t res = iconv (cd, &pin, &inbytesleft, &pout, &outbytesleft);
600 int err = errno;
601 iconv_close (cd);
602
603 //trace ("iconv -f %s -t %s '%s': returned %d, inbytes %d/%d, outbytes %d/%d, errno=%d\n", cs_in, cs_out, in, (int)res, inlen, (int)inbytesleft, outlen, (int)outbytesleft, err);
604 if (res == -1) {
605 return -1;
606 }
607 out[pout-out] = 0;
608 //trace ("iconv out: %s (len=%d)\n", out, pout - out);
609 return pout - out;
610 #elif defined(HAVE_ICU)
611 int status = 0;
612 trace ("ICU convert from %s to %s input %s\n", cs_in, cs_out, in);
613 int32_t len = ucnv_convert (cs_out, cs_in, out, outlen, in, inlen, &status);
614 out[len] = 0;
615 trace ("ICU out: %s\n", out);
616 return len;
617 #else
618 int len = ddb_iconv (cs_out, cs_in, out, outlen, in, inlen);
619 return len;
620 #endif
621 }
622
623 #define ID3V1_GENRE_COUNT (sizeof(junk_genretbl) / sizeof (char *) - 1)
624 static const char *junk_genretbl[] = {
625 "Blues",
626 "Classic Rock",
627 "Country",
628 "Dance",
629 "Disco",
630 "Funk",
631 "Grunge",
632 "Hip-Hop",
633 "Jazz",
634 "Metal",
635 "New Age",
636 "Oldies",
637 "Other",
638 "Pop",
639 "R&B",
640 "Rap",
641 "Reggae",
642 "Rock",
643 "Techno",
644 "Industrial",
645 "Alternative",
646 "Ska",
647 "Death Metal",
648 "Pranks",
649 "Soundtrack",
650 "Euro-Techno",
651 "Ambient",
652 "Trip-Hop",
653 "Vocal",
654 "Jazz+Funk",
655 "Fusion",
656 "Trance",
657 "Classical",
658 "Instrumental",
659 "Acid",
660 "House",
661 "Game",
662 "Sound Clip",
663 "Gospel",
664 "Noise",
665 "AlternRock",
666 "Bass",
667 "Soul",
668 "Punk",
669 "Space",
670 "Meditative",
671 "Instrumental Pop",
672 "Instrumental Rock",
673 "Ethnic",
674 "Gothic",
675 "Darkwave",
676 "Techno-Industrial",
677 "Electronic",
678 "Pop-Folk",
679 "Eurodance",
680 "Dream",
681 "Southern Rock",
682 "Comedy",
683 "Cult",
684 "Gangsta",
685 "Top 40",
686 "Christian Rap",
687 "Pop/Funk",
688 "Jungle",
689 "Native American",
690 "Cabaret",
691 "New Wave",
692 "Psychedelic",
693 "Rave",
694 "Showtunes",
695 "Trailer",
696 "Lo-Fi",
697 "Tribal",
698 "Acid Punk",
699 "Acid Jazz",
700 "Polka",
701 "Retro",
702 "Musical",
703 "Rock & Roll",
704 "Hard Rock",
705 "Folk",
706 "Folk-Rock",
707 "National Folk",
708 "Swing",
709 "Fast Fusion",
710 "Bebob",
711 "Latin",
712 "Revival",
713 "Celtic",
714 "Bluegrass",
715 "Avantgarde",
716 "Gothic Rock",
717 "Progressive Rock",
718 "Psychedelic Rock",
719 "Symphonic Rock",
720 "Slow Rock",
721 "Big Band",
722 "Chorus",
723 "Easy Listening",
724 "Acoustic",
725 "Humour",
726 "Speech",
727 "Chanson",
728 "Opera",
729 "Chamber Music",
730 "Sonata",
731 "Symphony",
732 "Booty Bass",
733 "Primus",
734 "Porn Groove",
735 "Satire",
736 "Slow Jam",
737 "Club",
738 "Tango",
739 "Samba",
740 "Folklore",
741 "Ballad",
742 "Power Ballad",
743 "Rhythmic Soul",
744 "Freestyle",
745 "Duet",
746 "Punk Rock",
747 "Drum Solo",
748 "Acapella",
749 "Euro-House",
750 "Dance Hall",
751 "Goa",
752 "Drum & Bass",
753 "Club-House",
754 "Hardcore",
755 "Terror",
756 "Indie",
757 "BritPop",
758 "Negerpunk",
759 "Polsk Punk",
760 "Beat",
761 "Christian Gangsta",
762 "Heavy Metal",
763 "Black Metal",
764 "Crossover",
765 "Contemporary C",
766 "Christian Rock",
767 "Merengue",
768 "Salsa",
769 "Thrash Metal",
770 "Anime",
771 "JPop",
772 "SynthPop",
773 "Abstract",
774 "Art Rock",
775 "Baroque",
776 "Bhangra",
777 "Big Beat",
778 "Breakbeat",
779 "Chillout",
780 "Downtempo",
781 "Dub",
782 "EBM",
783 "Eclectic",
784 "Electro",
785 "Electroclash",
786 "Emo",
787 "Experimental",
788 "Garage",
789 "Global",
790 "IDM",
791 "Illbient",
792 "Industro-Goth",
793 "Jam Band",
794 "Krautrock",
795 "Leftfield",
796 "Lounge",
797 "Math Rock",
798 "New Romantic",
799 "Nu-Breakz",
800 "Post-Punk",
801 "Post-Rock",
802 "Psytrance",
803 "Shoegaze",
804 "Space Rock",
805 "Trop Rock",
806 "World Music",
807 "Neoclassical",
808 "Audiobook",
809 "Audio Theatre",
810 "Neue Deutsche Welle",
811 "Podcast",
812 "Indie Rock",
813 "G-Funk",
814 "Dubstep",
815 "Garage Rock",
816 "Psybient",
817 NULL
818 };
819
820 static int
can_be_russian(const signed char * str,int size)821 can_be_russian (const signed char *str, int size) {
822 if (!enable_cp1251_detection) {
823 return 0;
824 }
825 int latin = 0;
826 int rus = 0;
827 int rus_in_row = 0;
828 int max_rus_row = 0;
829 int n = 0;
830 for (; n < size; str++, n++) {
831 if ((*str >= 'A' && *str <= 'Z')
832 || *str >= 'a' && *str <= 'z') {
833 if (rus_in_row > max_rus_row) {
834 max_rus_row = rus_in_row;
835 }
836 rus_in_row = 0;
837 latin++;
838 }
839 else if (*str < 0) {
840 rus_in_row++;
841 rus++;
842 }
843 }
844 if (rus > latin/2 || (max_rus_row > 4)) {
845 return 1;
846 }
847 return 0;
848 }
849
850 static int
can_be_chinese(const uint8_t * str,int sz)851 can_be_chinese (const uint8_t *str, int sz) {
852 if (!enable_cp936_detection) {
853 return 0;
854 }
855 int len = strlen (str);
856 for (int i = 0; i < sz; str++, i++) {
857 if (i < len-3
858 && (*str >= 0x81 && *str <= 0xFE )
859 && (*(str+1) >= 0x30 && *(str+1) <= 0x39)
860 && (*(str+2) >= 0x81 && *(str+2) <= 0xFE)
861 && (*(str+3) >= 0x30 && *(str+3) <= 0x39)) {
862 return 1;
863 }
864 if (i < len - 1
865 && (*str >= 0x81 && *str <= 0xFE )
866 && ((*(str+1) >= 0x40 && *(str+1) <= 0x7E)
867 || (*(str+1) >= 0x80 && *(str+1) <= 0xFE))) {
868 return 1;
869 }
870 }
871 return 0;
872 }
873
874 static int
can_be_shift_jis(const unsigned char * str,int size)875 can_be_shift_jis (const unsigned char *str, int size) {
876 unsigned char out[size*4];
877
878 if (size < 2) {
879 return 0;
880 }
881
882 const unsigned char *p = str;
883 int s = size;
884 while (s >= 2) {
885 if ((((p[0] >= 0x81 && p[0] <= 0x84) || (p[0] >= 0x87 && p[0] <= 0x9f))
886 && ((p[1] >= 0x40 && p[1] <= 0x9e) || (p[1] >= 0x9f && p[1] <= 0xfc)))
887 || ((p[0] >= 0xe0 && p[0] <= 0xef)
888 && ((p[1] >= 0x40 && p[1] <= 0x9e) || (p[1] >= 0x9f && p[1] <= 0xfc)))) {
889 break;
890 }
891 s--;
892 p++;
893 }
894
895 if (s >= 2) {
896 if (junk_iconv (str, size, out, sizeof (out), "shift-jis", UTF8_STR) >= 0) {
897 return 1;
898 }
899 }
900 return 0;
901
902 }
903
904
905 static char *
convstr_id3v2(int version,uint8_t encoding,const uint8_t * str,int sz)906 convstr_id3v2 (int version, uint8_t encoding, const uint8_t *str, int sz) {
907 const char *enc = NULL;
908
909 // detect encoding
910 if (version == 4 && encoding == 2) {
911 enc = "UTF-16BE";
912 }
913 else if (version == 4 && encoding == 3) {
914 enc = UTF8_STR;
915 }
916 else if (encoding == 0) {
917 if (can_be_chinese (str, sz)) {
918 // hack to add cp936 support
919 enc = "cp936";
920 }
921 else if (can_be_russian (str, sz)) {
922 // hack to add limited cp1251 recoding support
923 enc = "cp1251";
924 }
925 else {
926 enc = "cp1252";
927 }
928 }
929 else if (encoding != 1 && !(version == 4 && encoding == 3)){
930 return NULL; // invalid encoding
931 }
932
933 if (encoding == 1) { // detect kind of unicode used
934 if (sz < 2) {
935 return NULL;
936 }
937 if (version < 4) {
938 if (str[0] == 0xff && str[1] == 0xfe) {
939 enc = "UCS-2LE";
940 str += 2;
941 sz -= 2;
942 }
943 else if (str[1] == 0xff && str[0] == 0xfe) {
944 enc = "UCS-2BE";
945 str += 2;
946 sz -= 2;
947 }
948 else {
949 trace ("invalid ucs-2 signature %x %x\n", (int)str[0], (int)str[1]);
950 enc = "UCS-2LE";
951 // NOTE: this is an assumption, might break in the future.
952 }
953 }
954 else {
955 enc = "UTF-16";
956 }
957 }
958
959 trace ("encoding: %s\n", enc);
960
961 int converted_sz = 0;
962
963 int outlen = sz*4+1;
964 char *out = malloc (outlen);
965 if ((converted_sz = junk_iconv (str, sz, out, outlen, enc, UTF8_STR)) < 0) {
966 free (out);
967 return NULL;
968 }
969 // trace ("%s -> %s\n", str, out);
970 int n;
971 for (n = 0; n < converted_sz; n++) {
972 if (out[n] == 0 && n != converted_sz-1) {
973 out[n] = '\n';
974 }
975 }
976 // trim trailing linebreaks
977 for (n = converted_sz-1; n >= 0; n--) {
978 if ((uint8_t)out[n] <= 32) {
979 out[n] = 0;
980 }
981 else {
982 break;
983 }
984 }
985 return out;
986 }
987
988 static const char *
convstr_id3v1(const char * str,int sz,const char * charset,char * out,int outsize)989 convstr_id3v1 (const char* str, int sz, const char *charset, char *out, int outsize) {
990 if (!charset) {
991 return str;
992 }
993 int i;
994 for (i = 0; i < sz; i++) {
995 if (str[i] != ' ') {
996 break;
997 }
998 }
999 if (i == sz) {
1000 out[0] = 0;
1001 return out;
1002 }
1003
1004 int len = junk_iconv (str, sz, out, outsize, charset, UTF8_STR);
1005 if (len >= 0) {
1006 return out;
1007 }
1008 return NULL;
1009 }
1010
1011 static void
str_trim_right(uint8_t * str,int len)1012 str_trim_right (uint8_t *str, int len) {
1013 uint8_t *p = str + len - 1;
1014 while (p >= str && *p <= 0x20) {
1015 p--;
1016 }
1017 p++;
1018 *p = 0;
1019 }
1020
1021 int
junk_id3v1_read_int(playItem_t * it,char * buffer,const char ** charset)1022 junk_id3v1_read_int (playItem_t *it, char *buffer, const char **charset) {
1023 if (!buffer) {
1024 return -1;
1025 }
1026
1027 if (it) {
1028 if (memcmp (buffer, "TAG", 3)) {
1029 return -1; // no tag
1030 }
1031 const char *cs = NULL;
1032 charset = &cs;
1033 int res = junk_id3v1_read_int (NULL, buffer, charset);
1034 if (res) {
1035 return res;
1036 }
1037 }
1038
1039 if (!charset) {
1040 return -1;
1041 }
1042
1043 char title[31];
1044 char artist[31];
1045 char album[31];
1046 char year[5];
1047 char comment[31];
1048 uint8_t genreid;
1049 uint8_t tracknum;
1050 const char *genre = NULL;
1051 memset (title, 0, 31);
1052 memset (artist, 0, 31);
1053 memset (album, 0, 31);
1054 memset (year, 0, 5);
1055 memset (comment, 0, 31);
1056 memcpy (title, &buffer[3], 30);
1057 str_trim_right (title, 30);
1058 memcpy (artist, &buffer[3+30], 30);
1059 str_trim_right (artist, 30);
1060 memcpy (album, &buffer[3+60], 30);
1061 str_trim_right (album, 30);
1062 memcpy (year, &buffer[3+90], 4);
1063 str_trim_right (year, 4);
1064 memcpy (comment, &buffer[3+94], 30);
1065 str_trim_right (comment, 30);
1066 genreid = buffer[3+124];
1067 tracknum = 0;
1068 if (it) {
1069 if (comment[28] == 0 && comment[29] != 0) {
1070 tracknum = comment[29];
1071 }
1072
1073 // 255 = "None",
1074 // "CR" = "Cover" (id3v2)
1075 // "RX" = "Remix" (id3v2)
1076 if (genreid == 0xff) {
1077 //genre = "None";
1078 }
1079 else if (genreid < ID3V1_GENRE_COUNT) {
1080 genre = junk_genretbl[genreid];
1081 }
1082 }
1083
1084 // add meta
1085 // trace ("%s - %s - %s - %s - %s - %s\n", title, artist, album, year, comment, genre);
1086 if (!it) {
1087 char buf[129];
1088 char *p = buf;
1089 strcpy (p, title);
1090 p += strlen (title);
1091 strcpy (p, artist);
1092 p += strlen (artist);
1093 strcpy (p, album);
1094 p += strlen (album);
1095 strcpy (p, year);
1096 p += strlen (year);
1097 strcpy (p, comment);
1098 *charset = junk_detect_charset (buf);
1099 return 0;
1100 }
1101
1102 char utf8_value[150];
1103
1104 if (*title) {
1105 pl_add_meta (it, "title", convstr_id3v1 (title, (int)strlen (title), *charset, utf8_value, sizeof (utf8_value)));
1106 }
1107 if (*artist) {
1108 pl_add_meta (it, "artist", convstr_id3v1 (artist, (int)strlen (artist), *charset, utf8_value, sizeof (utf8_value)));
1109 }
1110 if (*album) {
1111 pl_add_meta (it, "album", convstr_id3v1 (album, (int)strlen (album), *charset, utf8_value, sizeof (utf8_value)));
1112 }
1113 if (*year) {
1114 pl_add_meta (it, "year", convstr_id3v1 (year, (int)strlen (year), *charset, utf8_value, sizeof (utf8_value)));
1115 }
1116 if (*comment) {
1117 pl_add_meta (it, "comment", convstr_id3v1 (comment, (int)strlen (comment), *charset, utf8_value, sizeof (utf8_value)));
1118 }
1119 if (genre && *genre) {
1120 pl_add_meta (it, "genre", convstr_id3v1 (genre, (int)strlen (genre), *charset, utf8_value, sizeof (utf8_value)));
1121 }
1122 if (tracknum != 0) {
1123 char s[4];
1124 snprintf (s, 4, "%d", tracknum);
1125 pl_add_meta (it, "track", s);
1126 }
1127
1128 uint32_t f = pl_get_item_flags (it);
1129 f |= DDB_TAG_ID3V1;
1130 pl_set_item_flags (it, f);
1131
1132 return 0;
1133 }
1134
1135 // should read both id3v1 and id3v1.1
1136 int
junk_id3v1_read(playItem_t * it,DB_FILE * fp)1137 junk_id3v1_read (playItem_t *it, DB_FILE *fp) {
1138 uint8_t id3[128];
1139
1140 if (deadbeef->fseek (fp, -128, SEEK_END) == -1) {
1141 return -1;
1142 }
1143 if (deadbeef->fread (id3, 1, 128, fp) != 128) {
1144 return -1;
1145 }
1146
1147 return junk_id3v1_read_int (it, id3, NULL);
1148 }
1149
1150 int
junk_id3v1_write2(int fd,playItem_t * it,const char * enc)1151 junk_id3v1_write2 (int fd, playItem_t *it, const char *enc) {
1152 char title[30] = "";
1153 char artist[30] = "";
1154 char album[30] = "";
1155 char year[4] = "";
1156 char comment[28] = "";
1157 uint8_t genreid = 0xff;
1158 uint8_t tracknum = 0;
1159
1160 const char *meta;
1161
1162 pl_lock ();
1163
1164 #define conv(name, store) {\
1165 memset (store, 0x20, sizeof (store));\
1166 meta = pl_find_meta (it, name);\
1167 if (meta) {\
1168 char temp[1000];\
1169 int l = junk_iconv (meta, strlen (meta), temp, sizeof (temp), UTF8_STR, enc);\
1170 if (l == -1) {\
1171 memset (store, 0, sizeof (store));\
1172 }\
1173 else {\
1174 strncpy (store, temp, sizeof (store));\
1175 }\
1176 char *cr = strchr (store, '\n');\
1177 if (cr) {\
1178 *cr = 0;\
1179 }\
1180 }\
1181 }
1182
1183 conv ("title", title);
1184 conv ("artist", artist);
1185 conv ("album", album);
1186 conv ("year", year);
1187 conv ("comment", comment);
1188
1189 #undef conv
1190
1191 // tracknum
1192 meta = pl_find_meta (it, "track");
1193 if (meta) {
1194 tracknum = atoi (meta);
1195 }
1196
1197 // find genre
1198 meta = pl_find_meta (it, "genre");
1199 if (meta) {
1200 for (int i = 0; junk_genretbl[i]; i++) {
1201 if (!strcasecmp (meta, junk_genretbl[i])) {
1202 genreid = i;
1203 break;
1204 }
1205 }
1206 // workaround for the id3v1 std spelling error
1207 if (genreid == 0xff && !strcasecmp (meta, "Psychadelic")) {
1208 genreid = 67;
1209 }
1210 }
1211
1212 pl_unlock ();
1213
1214 if (write (fd, "TAG", 3) != 3) {
1215 trace ("junk_id3v1_write: failed to write signature\n");
1216 return -1;
1217 }
1218 if (write (fd, title, sizeof (title)) != sizeof (title)) {
1219 trace ("junk_id3v1_write: failed to write title\n");
1220 return -1;
1221 }
1222 if (write (fd, artist, sizeof (artist)) != sizeof (artist)) {
1223 trace ("junk_id3v1_write: failed to write artist\n");
1224 return -1;
1225 }
1226 if (write (fd, album, sizeof (album)) != sizeof (album)) {
1227 trace ("junk_id3v1_write: failed to write album\n");
1228 return -1;
1229 }
1230 if (write (fd, year, sizeof (year)) != sizeof (year)) {
1231 trace ("junk_id3v1_write: failed to write year\n");
1232 return -1;
1233 }
1234 if (write (fd, comment, sizeof (comment)) != sizeof (comment)) {
1235 trace ("junk_id3v1_write: failed to write comment\n");
1236 return -1;
1237 }
1238 uint8_t zero = 0;
1239 if (write (fd, &zero, 1) != 1) {
1240 trace ("junk_id3v1_write: failed to write id3v1.1 marker\n");
1241 return -1;
1242 }
1243 if (write (fd, &tracknum, 1) != 1) {
1244 trace ("junk_id3v1_write: failed to write track\n");
1245 return -1;
1246 }
1247 if (write (fd, &genreid, 1) != 1) {
1248 trace ("junk_id3v1_write: failed to write genre\n");
1249 return -1;
1250 }
1251 return 0;
1252 }
1253
1254 int
junk_id3v1_write(FILE * fp,playItem_t * it,const char * enc)1255 junk_id3v1_write (FILE *fp, playItem_t *it, const char *enc) {
1256 char title[30] = "";
1257 char artist[30] = "";
1258 char album[30] = "";
1259 char year[4] = "";
1260 char comment[28] = "";
1261 uint8_t genreid = 0xff;
1262 uint8_t tracknum = 0;
1263
1264 const char *meta;
1265
1266 pl_lock ();
1267
1268 #define conv(name, store) {\
1269 memset (store, 0x20, sizeof (store));\
1270 meta = pl_find_meta (it, name);\
1271 if (meta) {\
1272 char temp[1000];\
1273 int l = junk_iconv (meta, strlen (meta), temp, sizeof (temp), UTF8_STR, enc);\
1274 if (l == -1) {\
1275 memset (store, 0, sizeof (store));\
1276 }\
1277 else {\
1278 strncpy (store, temp, sizeof (store));\
1279 }\
1280 char *cr = strchr (store, '\n');\
1281 if (cr) {\
1282 *cr = 0;\
1283 }\
1284 }\
1285 }
1286
1287 conv ("title", title);
1288 conv ("artist", artist);
1289 conv ("album", album);
1290 conv ("year", year);
1291 conv ("comment", comment);
1292
1293 #undef conv
1294
1295 // tracknum
1296 meta = pl_find_meta (it, "track");
1297 if (meta) {
1298 tracknum = atoi (meta);
1299 }
1300
1301 // find genre
1302 meta = pl_find_meta (it, "genre");
1303 if (meta) {
1304 for (int i = 0; junk_genretbl[i]; i++) {
1305 if (!strcasecmp (meta, junk_genretbl[i])) {
1306 genreid = i;
1307 break;
1308 }
1309 }
1310 // workaround for the id3v1 std spelling error
1311 if (genreid == 0xff && !strcasecmp (meta, "Psychadelic")) {
1312 genreid = 67;
1313 }
1314 }
1315
1316 pl_unlock ();
1317
1318 if (fwrite ("TAG", 1, 3, fp) != 3) {
1319 trace ("junk_id3v1_write: failed to write signature\n");
1320 return -1;
1321 }
1322 if (fwrite (title, 1, sizeof (title), fp) != sizeof (title)) {
1323 trace ("junk_id3v1_write: failed to write title\n");
1324 return -1;
1325 }
1326 if (fwrite (artist, 1, sizeof (artist), fp) != sizeof (artist)) {
1327 trace ("junk_id3v1_write: failed to write artist\n");
1328 return -1;
1329 }
1330 if (fwrite (album, 1, sizeof (album), fp) != sizeof (album)) {
1331 trace ("junk_id3v1_write: failed to write album\n");
1332 return -1;
1333 }
1334 if (fwrite (year, 1, sizeof (year), fp) != sizeof (year)) {
1335 trace ("junk_id3v1_write: failed to write year\n");
1336 return -1;
1337 }
1338 if (fwrite (comment, 1, sizeof (comment), fp) != sizeof (comment)) {
1339 trace ("junk_id3v1_write: failed to write comment\n");
1340 return -1;
1341 }
1342 uint8_t zero = 0;
1343 if (fwrite (&zero, 1, 1, fp) != 1) {
1344 trace ("junk_id3v1_write: failed to write id3v1.1 marker\n");
1345 return -1;
1346 }
1347 if (fwrite (&tracknum, 1, 1, fp) != 1) {
1348 trace ("junk_id3v1_write: failed to write track\n");
1349 return -1;
1350 }
1351 if (fwrite (&genreid, 1, 1, fp) != 1) {
1352 trace ("junk_id3v1_write: failed to write genre\n");
1353 return -1;
1354 }
1355 return 0;
1356 }
1357
1358 int64_t
junk_id3v1_find2(DB_FILE * fp)1359 junk_id3v1_find2 (DB_FILE *fp) {
1360 uint8_t buffer[3];
1361 if (deadbeef->fseek (fp, -128, SEEK_END) == -1) {
1362 return -1;
1363 }
1364 if (deadbeef->fread (buffer, 1, 3, fp) != 3) {
1365 return -1;
1366 }
1367 if (memcmp (buffer, "TAG", 3)) {
1368 return -1; // no tag
1369 }
1370 return deadbeef->ftell (fp) - 3;
1371 }
1372
1373 int
junk_id3v1_find(DB_FILE * fp)1374 junk_id3v1_find (DB_FILE *fp) {
1375 int64_t pos = junk_id3v1_find2 (fp);
1376 // 32 bit overflow protection
1377 if (pos > 0x7fffffff) {
1378 return -1;
1379 }
1380 return pos;
1381 }
1382
1383 int64_t
junk_apev2_find2(DB_FILE * fp,int32_t * psize,uint32_t * pflags,uint32_t * pnumitems)1384 junk_apev2_find2 (DB_FILE *fp, int32_t *psize, uint32_t *pflags, uint32_t *pnumitems) {
1385 uint8_t header[32];
1386 if (deadbeef->fseek (fp, -32, SEEK_END) == -1) {
1387 return -1; // something bad happened
1388 }
1389
1390 if (deadbeef->fread (header, 1, 32, fp) != 32) {
1391 return -1; // something bad happened
1392 }
1393 if (strncmp (header, "APETAGEX", 8)) {
1394 // try to skip 128 bytes backwards (id3v1)
1395 if (deadbeef->fseek (fp, -128-32, SEEK_END) == -1) {
1396 return -1; // something bad happened
1397 }
1398 if (deadbeef->fread (header, 1, 32, fp) != 32) {
1399 return -1; // something bad happened
1400 }
1401 if (strncmp (header, "APETAGEX", 8)) {
1402 return -1; // no ape tag here
1403 }
1404 }
1405
1406 uint32_t version = extract_i32_le (&header[8]);
1407 int32_t size = extract_i32_le (&header[12]);
1408 uint32_t numitems = extract_i32_le (&header[16]);
1409 uint32_t flags = extract_i32_le (&header[20]);
1410
1411 trace ("APEv%d, size=%d, items=%d, flags=%x\n", version, size, numitems, flags);
1412
1413 // size contains footer, but not header, so add header size
1414 if (flags & (1<<31)) {
1415 size += 32;
1416 }
1417
1418 // seek to beginning of the tag/header
1419 if (deadbeef->fseek (fp, -size, SEEK_CUR) == -1) {
1420 trace ("failed to seek to tag start (-%d)\n", size);
1421 return -1;
1422 }
1423 *psize = size;
1424 *pflags = flags;
1425 *pnumitems = numitems;
1426 return deadbeef->ftell (fp);
1427 }
1428
1429 int
junk_apev2_find(DB_FILE * fp,int32_t * psize,uint32_t * pflags,uint32_t * pnumitems)1430 junk_apev2_find (DB_FILE *fp, int32_t *psize, uint32_t *pflags, uint32_t *pnumitems) {
1431 int64_t pos = junk_apev2_find2 (fp, psize, pflags, pnumitems);
1432 // 32 bit overflow protection
1433 if (pos > 0x7fffffff) {
1434 return -1;
1435 }
1436 return pos;
1437 }
1438
1439 int
junk_find_id3v1(DB_FILE * fp)1440 junk_find_id3v1 (DB_FILE *fp) {
1441 if (deadbeef->fseek (fp, -128, SEEK_END) == -1) {
1442 return -1;
1443 }
1444 char buffer[3];
1445 if (deadbeef->fread (buffer, 1, 3, fp) != 3) {
1446 return -1;
1447 }
1448 if (memcmp (buffer, "TAG", 3)) {
1449 return -1; // no tag
1450 }
1451 return deadbeef->ftell (fp) - 3;
1452 }
1453
1454 int
junk_add_track_meta(playItem_t * it,const char * track)1455 junk_add_track_meta (playItem_t *it, const char *track) {
1456 char *slash = strchr (track, '/');
1457 if (slash) {
1458 // split into track/number
1459 *slash = 0;
1460 slash++;
1461 pl_add_meta (it, "numtracks", slash);
1462 }
1463 pl_add_meta (it, "track", track);
1464 return 0;
1465 }
1466
1467 int
junk_add_disc_meta(playItem_t * it,const char * disc)1468 junk_add_disc_meta (playItem_t *it, const char *disc) {
1469 char *slash = strchr (disc, '/');
1470 if (slash) {
1471 // split into track/number
1472 *slash = 0;
1473 slash++;
1474 pl_add_meta (it, "numdiscs", slash);
1475 }
1476 pl_add_meta (it, "disc", disc);
1477 return 0;
1478 }
1479
1480 int
junk_apev2_add_frame(playItem_t * it,DB_apev2_tag_t * tag_store,DB_apev2_frame_t ** tail,uint32_t itemsize,uint32_t itemflags,const char * key,const uint8_t * value)1481 junk_apev2_add_frame (playItem_t *it, DB_apev2_tag_t *tag_store, DB_apev2_frame_t **tail, uint32_t itemsize, uint32_t itemflags, const char *key, const uint8_t *value) {
1482 if (tag_store) {
1483 DB_apev2_frame_t *frm = malloc (sizeof (DB_apev2_frame_t) + itemsize);
1484 memset (frm, 0, sizeof (DB_apev2_tag_t));
1485 frm->flags = itemflags;
1486 strcpy (frm->key, key);
1487 trace ("*** stored frame %s flags %X\n", key, itemflags);
1488 frm->size = itemsize;
1489 memcpy (frm->data, value, itemsize);
1490 if (*tail) {
1491 (*tail)->next = frm;
1492 }
1493 else {
1494 tag_store->frames = frm;
1495 }
1496 *tail = frm;
1497 }
1498
1499 if (it) {
1500 int valuetype = ((itemflags >> 1) & 3);
1501 // add metainfo only if it's textual
1502 if (valuetype == 0 && (itemsize < MAX_TEXT_FRAME_SIZE || (!strcasecmp (key, "cuesheet") && itemsize < MAX_CUESHEET_FRAME_SIZE))) {
1503 if (!u8_valid (value, itemsize, NULL)) {
1504 trace ("junk_read_ape_full: bad encoding in text frame %s\n", key);
1505 return -1;
1506 }
1507
1508 int m;
1509 for (m = 0; frame_mapping[m]; m += FRAME_MAPPINGS) {
1510 if (frame_mapping[m + MAP_APEV2] && !strcasecmp (key, frame_mapping[m + MAP_APEV2])) {
1511 if (!strcmp (frame_mapping[m+MAP_DDB], "track")) {
1512 junk_add_track_meta (it, value);
1513 }
1514 else {
1515 trace ("pl_append_meta %s %s\n", frame_mapping[m+MAP_DDB], value);
1516 pl_append_meta (it, frame_mapping[m+MAP_DDB], value);
1517 }
1518 break;
1519 }
1520 }
1521
1522 trace ("apev2 %s=%s\n", key, value);
1523
1524 if (!frame_mapping[m]) {
1525 if (!strncasecmp (key, "replaygain_album_gain", 21)) {
1526 pl_set_item_replaygain (it, DDB_REPLAYGAIN_ALBUMGAIN, atof (value));
1527 trace ("album_gain=%s\n", value);
1528 }
1529 else if (!strncasecmp (key, "replaygain_album_peak", 21)) {
1530 pl_set_item_replaygain (it, DDB_REPLAYGAIN_ALBUMPEAK, atof (value));
1531 trace ("album_peak=%s\n", value);
1532 }
1533 else if (!strncasecmp (key, "replaygain_track_gain", 21)) {
1534 pl_set_item_replaygain (it, DDB_REPLAYGAIN_TRACKGAIN, atof (value));
1535 trace ("track_gain=%s\n", value);
1536 }
1537 else if (!strncasecmp (key, "replaygain_track_peak", 21)) {
1538 pl_set_item_replaygain (it, DDB_REPLAYGAIN_TRACKPEAK, atof (value));
1539 trace ("track_peak=%s\n", value);
1540 }
1541 else {
1542 trace ("%s=%s\n", key, value);
1543 pl_append_meta (it, key, value);;
1544 }
1545 }
1546 }
1547 }
1548 return 0;
1549 }
1550
1551 int
junk_apev2_read_full_mem(playItem_t * it,DB_apev2_tag_t * tag_store,char * mem,int memsize)1552 junk_apev2_read_full_mem (playItem_t *it, DB_apev2_tag_t *tag_store, char *mem, int memsize) {
1553 char *end = mem+memsize;
1554 #define STEP(x,y) {mem+=(x);if(mem+(y)>end) {trace ("fail %d\n", (x));return -1;}}
1555
1556 char *header = mem;
1557
1558 DB_apev2_frame_t *tail = NULL;
1559
1560 uint32_t version = extract_i32_le (&header[0]);
1561 int32_t size = extract_i32_le (&header[4]);
1562 uint32_t numitems = extract_i32_le (&header[8]);
1563 uint32_t flags = extract_i32_le (&header[12]);
1564
1565 trace ("APEv%d, size=%d, items=%d, flags=%x\n", version, size, numitems, flags);
1566 if (it) {
1567 uint32_t f = pl_get_item_flags (it);
1568 f |= DDB_TAG_APEV2;
1569 pl_set_item_flags (it, f);
1570 }
1571
1572 STEP(24, 8);
1573
1574 int i;
1575 for (i = 0; i < numitems; i++) {
1576 trace ("reading item %d\n", i);
1577 uint8_t *buffer = mem;
1578
1579 uint32_t itemsize = extract_i32_le (&buffer[0]);
1580 uint32_t itemflags = extract_i32_le (&buffer[4]);
1581
1582 STEP(8, 1);
1583 trace ("size=%d, flags=%x\n", itemsize, itemflags);
1584
1585 // read key until 0 (stupid and slow)
1586 char key[256];
1587 int keysize = 0;
1588 while (keysize <= 255 && mem < end) {
1589 key[keysize] = *mem;
1590 mem++;
1591 if (key[keysize] == 0) {
1592 break;
1593 }
1594 if (key[keysize] < 0x20) {
1595 trace ("nonascii chars\n");
1596 return -1; // non-ascii chars and chars with codes 0..0x1f not allowed in ape item keys
1597 }
1598 keysize++;
1599 }
1600 key[255] = 0;
1601 trace ("item %d, size %d, flags %08x, keysize %d, key %s\n", i, itemsize, itemflags, keysize, key);
1602 // read value
1603 if (itemsize <= MAX_APEV2_FRAME_SIZE) // just a sanity check
1604 {
1605 STEP(0,itemsize);
1606 uint8_t *value = malloc (itemsize+1);
1607 if (!value) {
1608 trace ("junk_read_ape_full: failed to allocate %d bytes\n", itemsize+1);
1609 return -1;
1610 }
1611 memcpy (value, mem, itemsize);
1612 value[itemsize] = 0;
1613
1614 // replace 0s with \n
1615 uint8_t *p = value;
1616 while (p < value + itemsize - 1) {
1617 if (*p == 0) {
1618 *p = '\n';
1619 }
1620 p++;
1621 }
1622
1623 junk_apev2_add_frame (it, tag_store, &tail, itemsize, itemflags, key, value);
1624
1625 free (value);
1626 STEP(itemsize, 8);
1627 }
1628 else {
1629 STEP(itemsize,8);
1630 }
1631 }
1632 return 0;
1633 }
1634
1635 int
junk_apev2_read_full(playItem_t * it,DB_apev2_tag_t * tag_store,DB_FILE * fp)1636 junk_apev2_read_full (playItem_t *it, DB_apev2_tag_t *tag_store, DB_FILE *fp) {
1637 // try to read footer, position must be already at the EOF right before
1638 // id3v1 (if present)
1639
1640 DB_apev2_frame_t *tail = NULL;
1641
1642 uint8_t header[32];
1643 if (deadbeef->fseek (fp, -32, SEEK_END) == -1) {
1644 return -1; // something bad happened
1645 }
1646
1647 if (deadbeef->fread (header, 1, 32, fp) != 32) {
1648 return -1; // something bad happened
1649 }
1650 if (strncmp (header, "APETAGEX", 8)) {
1651 // try to skip 128 bytes backwards (id3v1)
1652 if (deadbeef->fseek (fp, -128-32, SEEK_END) == -1) {
1653 return -1; // something bad happened
1654 }
1655 if (deadbeef->fread (header, 1, 32, fp) != 32) {
1656 return -1; // something bad happened
1657 }
1658 if (strncmp (header, "APETAGEX", 8)) {
1659 return -1; // no ape tag here
1660 }
1661 }
1662
1663 // end of footer must be 0
1664 // if (memcmp (&header[24], "\0\0\0\0\0\0\0\0", 8)) {
1665 // trace ("bad footer\n");
1666 // return -1;
1667 // }
1668
1669 uint32_t version = extract_i32_le (&header[8]);
1670 int32_t size = extract_i32_le (&header[12]);
1671 uint32_t numitems = extract_i32_le (&header[16]);
1672 uint32_t flags = extract_i32_le (&header[20]);
1673
1674 trace ("APEv%d, size=%d, items=%d, flags=%x\n", version, size, numitems, flags);
1675 if (it) {
1676 uint32_t f = pl_get_item_flags (it);
1677 f |= DDB_TAG_APEV2;
1678 pl_set_item_flags (it, f);
1679 }
1680
1681 // now seek to beginning of the tag (exluding header)
1682 if (deadbeef->fseek (fp, -size, SEEK_CUR) == -1) {
1683 trace ("failed to seek to tag start (-%d)\n", size);
1684 return -1;
1685 }
1686
1687 int i;
1688 for (i = 0; i < numitems; i++) {
1689 uint8_t buffer[8];
1690 if (deadbeef->fread (buffer, 1, 8, fp) != 8) {
1691 return -1;
1692 }
1693 uint32_t itemsize = extract_i32_le (&buffer[0]);
1694 uint32_t itemflags = extract_i32_le (&buffer[4]);
1695
1696 // read key until 0 (stupid and slow)
1697 char key[256];
1698 int keysize = 0;
1699 while (keysize <= 255) {
1700 if (deadbeef->fread (&key[keysize], 1, 1, fp) != 1) {
1701 return -1;
1702 }
1703 if (key[keysize] == 0) {
1704 break;
1705 }
1706 if (key[keysize] < 0x20) {
1707 return -1; // non-ascii chars and chars with codes 0..0x1f not allowed in ape item keys
1708 }
1709 keysize++;
1710 }
1711 key[255] = 0;
1712 trace ("item %d, size %d, flags %08x, keysize %d, key %s\n", i, itemsize, itemflags, keysize, key);
1713 // read value
1714 if (itemsize <= MAX_APEV2_FRAME_SIZE) // just a sanity check
1715 {
1716 uint8_t *value = malloc (itemsize+1);
1717 if (!value) {
1718 trace ("junk_read_ape_full: failed to allocate %d bytes\n", itemsize+1);
1719 return -1;
1720 }
1721 if (deadbeef->fread (value, 1, itemsize, fp) != itemsize) {
1722 trace ("junk_read_ape_full: failed to read %d bytes from file\n", itemsize);
1723 free (value);
1724 return -1;
1725 }
1726 value[itemsize] = 0;
1727
1728 if ((flags&6) == 0 && strncasecmp (key, "cover art ", 10)) {
1729 // replace 0s with \n
1730 uint8_t *p = value;
1731 while (p < value + itemsize - 1) {
1732 if (*p == 0) {
1733 *p = '\n';
1734 }
1735 p++;
1736 }
1737 }
1738
1739 junk_apev2_add_frame (it, tag_store, &tail, itemsize, itemflags, key, value);
1740 free (value);
1741 }
1742 else {
1743 // try to skip
1744 int err = deadbeef->fseek (fp, itemsize, SEEK_CUR);
1745 if (0 != err) {
1746 perror ("junklib: corrupted APEv2 tag\n");
1747 return -1;
1748 }
1749 }
1750 }
1751
1752 return 0;
1753 }
1754
1755 int
junk_apev2_read(playItem_t * it,DB_FILE * fp)1756 junk_apev2_read (playItem_t *it, DB_FILE *fp) {
1757 return junk_apev2_read_full (it, NULL, fp);
1758 }
1759
1760 int
junk_apev2_read_mem(playItem_t * it,char * mem,int size)1761 junk_apev2_read_mem (playItem_t *it, char *mem, int size) {
1762 return junk_apev2_read_full_mem (it, NULL, mem, size);
1763 }
1764
1765 int
junk_id3v2_find(DB_FILE * fp,int * psize)1766 junk_id3v2_find (DB_FILE *fp, int *psize) {
1767 if (deadbeef->fseek (fp, 0, SEEK_SET) == -1) {
1768 trace ("junk_id3v2_find: seek error\n");
1769 return -1;
1770 }
1771 uint8_t header[10];
1772 int pos = deadbeef->ftell (fp);
1773 if (pos == -1) {
1774 trace ("junk_id3v2_find: ftell error\n");
1775 return -1;
1776 }
1777 if (deadbeef->fread (header, 1, 10, fp) != 10) {
1778 trace ("junk_id3v2_find: read error\n");
1779 return -1; // too short
1780 }
1781 if (strncmp (header, "ID3", 3)) {
1782 return -1; // no tag
1783 }
1784 uint8_t flags = header[5];
1785 if (flags & 15) {
1786 return -1; // unsupported
1787 }
1788 int footerpresent = (flags & (1<<4)) ? 1 : 0;
1789 // check for bad size
1790 if ((header[9] & 0x80) || (header[8] & 0x80) || (header[7] & 0x80) || (header[6] & 0x80)) {
1791 return -1; // bad header
1792 }
1793 uint32_t size = (header[9] << 0) | (header[8] << 7) | (header[7] << 14) | (header[6] << 21);
1794 //trace ("junklib: leading junk size %d\n", size);
1795 *psize = size + 10 + 10 * footerpresent;
1796 return pos;
1797 }
1798
1799 int
junk_get_leading_size_stdio(FILE * fp)1800 junk_get_leading_size_stdio (FILE *fp) {
1801 uint8_t header[10];
1802 int pos = ftell (fp);
1803 if (fread (header, 1, 10, fp) != 10) {
1804 fseek (fp, pos, SEEK_SET);
1805 return -1; // too short
1806 }
1807 fseek (fp, pos, SEEK_SET);
1808 if (strncmp (header, "ID3", 3)) {
1809 return -1; // no tag
1810 }
1811 uint8_t flags = header[5];
1812 if (flags & 15) {
1813 return -1; // unsupported
1814 }
1815 int footerpresent = (flags & (1<<4)) ? 1 : 0;
1816 // check for bad size
1817 if ((header[9] & 0x80) || (header[8] & 0x80) || (header[7] & 0x80) || (header[6] & 0x80)) {
1818 return -1; // bad header
1819 }
1820 uint32_t size = (header[9] << 0) | (header[8] << 7) | (header[7] << 14) | (header[6] << 21);
1821 //trace ("junklib: leading junk size %d\n", size);
1822 return size + 10 + 10 * footerpresent;
1823 }
1824
1825 int
junk_get_leading_size(DB_FILE * fp)1826 junk_get_leading_size (DB_FILE *fp) {
1827 uint8_t header[10];
1828 int pos = deadbeef->ftell (fp);
1829 if (deadbeef->fread (header, 1, 10, fp) != 10) {
1830 deadbeef->fseek (fp, pos, SEEK_SET);
1831 trace ("junk_get_leading_size: file is too short\n");
1832 return -1; // too short
1833 }
1834 deadbeef->fseek (fp, pos, SEEK_SET);
1835 if (strncmp (header, "ID3", 3)) {
1836 trace ("junk_get_leading_size: no id3v2 found\n");
1837 return -1; // no tag
1838 }
1839 uint8_t flags = header[5];
1840 if (flags & 15) {
1841 trace ("unsupported flags in id3v2\n");
1842 return -1; // unsupported
1843 }
1844 int footerpresent = (flags & (1<<4)) ? 1 : 0;
1845 // check for bad size
1846 if ((header[9] & 0x80) || (header[8] & 0x80) || (header[7] & 0x80) || (header[6] & 0x80)) {
1847 trace ("bad header in id3v2\n");
1848 return -1; // bad header
1849 }
1850 uint32_t size = (header[9] << 0) | (header[8] << 7) | (header[7] << 14) | (header[6] << 21);
1851 //trace ("junklib: leading junk size %d\n", size);
1852 return size + 10 + 10 * footerpresent;
1853 }
1854
1855 int
junk_id3v2_unsync(uint8_t * out,int len,int maxlen)1856 junk_id3v2_unsync (uint8_t *out, int len, int maxlen) {
1857 uint8_t buf [maxlen];
1858 uint8_t *p = buf;
1859 int res = -1;
1860 for (int i = 0; i < len; i++) {
1861 *p++ = out[i];
1862 if (i < len - 1 && out[i] == 0xff && (out[i+1] & 0xe0) == 0xe0) {
1863 *p++ = 0;
1864 res = 0;
1865 }
1866 }
1867 if (!res) {
1868 res = p-buf;
1869 memcpy (out, buf, res);
1870 }
1871 return res;
1872 }
1873
1874 int
junk_id3v2_remove_frames(DB_id3v2_tag_t * tag,const char * frame_id)1875 junk_id3v2_remove_frames (DB_id3v2_tag_t *tag, const char *frame_id) {
1876 DB_id3v2_frame_t *prev = NULL;
1877 for (DB_id3v2_frame_t *f = tag->frames; f; ) {
1878 DB_id3v2_frame_t *next = f->next;
1879 if (!strcmp (f->id, frame_id)) {
1880 if (prev) {
1881 prev->next = f->next;
1882 }
1883 else {
1884 tag->frames = f->next;
1885 }
1886 free (f);
1887 }
1888 else {
1889 prev = f;
1890 }
1891 f = next;
1892 }
1893 return 0;
1894 }
1895
1896 // this function will split multiline values into separate frames
1897 DB_id3v2_frame_t *
junk_id3v2_add_text_frame(DB_id3v2_tag_t * tag,const char * frame_id,const char * value)1898 junk_id3v2_add_text_frame (DB_id3v2_tag_t *tag, const char *frame_id, const char *value) {
1899 // copy value to handle multiline strings
1900 size_t inlen = strlen (value);
1901 char buffer[inlen];
1902 char *pp = buffer;
1903 for (const char *p = value; *p; p++) {
1904 if (*p == '\n') {
1905 *pp++ = 0;
1906 if (tag->version[0] == 3) {
1907 inlen = p - value;
1908 break;
1909 }
1910 }
1911 else {
1912 *pp++ = *p;
1913 }
1914 }
1915
1916 if (!inlen) {
1917 return NULL;
1918 }
1919 uint8_t *out = NULL;
1920
1921 trace ("junklib: setting id3v2.%d text frame '%s' = '%s'\n", tag->version[0], frame_id, value);
1922
1923 int encoding = 0;
1924
1925 size_t outlen = -1;
1926 if (tag->version[0] == 4) {
1927 outlen = inlen;
1928 out = (uint8_t *)value;
1929 encoding = 3;
1930 }
1931 else {
1932 int bufsize = inlen * 4 + 1;
1933 out = malloc (bufsize);
1934 outlen = junk_iconv (value, inlen, out, bufsize, UTF8_STR, "cp1252");
1935 if (outlen == -1) {
1936 outlen = junk_iconv (value, inlen, out+2, bufsize - 2, UTF8_STR, "UCS-2LE");
1937 if (outlen <= 0) {
1938 return NULL;
1939 }
1940 out[0] = 0xff;
1941 out[1] = 0xfe;
1942 outlen += 2;
1943 trace ("successfully converted to ucs-2le (size=%d, bom: %x %x)\n", (int)outlen, out[0], out[1]);
1944 encoding = 1;
1945 }
1946 else {
1947 trace ("successfully converted to cp1252 (size=%d)\n", (int)outlen);
1948 }
1949 }
1950
1951 // make a frame
1952 int size = outlen + 1;
1953 trace ("calculated frame size = %d\n", size);
1954 DB_id3v2_frame_t *f = malloc (size + sizeof (DB_id3v2_frame_t));
1955 memset (f, 0, sizeof (DB_id3v2_frame_t));
1956 strcpy (f->id, frame_id);
1957 f->size = size;
1958 f->data[0] = encoding;
1959 memcpy (f->data + 1, out, outlen);
1960
1961 if (tag->version[0] != 4) {
1962 free (out);
1963 }
1964
1965 // append to tag
1966 DB_id3v2_frame_t *tail = NULL;
1967
1968 for (tail = tag->frames; tail && tail->next; tail = tail->next);
1969
1970 if (tail) {
1971 tail->next = f;
1972 }
1973 else {
1974 tag->frames = f;
1975 }
1976 tail = f;
1977
1978 return tail;
1979 }
1980
1981 DB_id3v2_frame_t *
junk_id3v2_add_comment_frame(DB_id3v2_tag_t * tag,const char * lang,const char * descr,const char * value)1982 junk_id3v2_add_comment_frame (DB_id3v2_tag_t *tag, const char *lang, const char *descr, const char *value) {
1983 trace ("junklib: setting 2.3 COMM frame lang=%s, descr='%s', data='%s'\n", lang, descr, value);
1984
1985 // make a frame
1986 size_t descrlen = strlen (descr);
1987 size_t outlen = strlen (value);
1988
1989 size_t inputsize = descrlen+outlen+1;
1990 char *input = malloc (inputsize);
1991
1992 memcpy (input, descr, descrlen);
1993 input[descrlen] = 0;
1994 memcpy (input+descrlen+1, value, outlen);
1995
1996 size_t buffersize = inputsize * 4;
1997 char *buffer = malloc (buffersize);
1998
1999 int enc = 0;
2000 int l;
2001
2002 if (tag->version[0] == 4) {
2003 // utf8
2004 enc = 3;
2005 memcpy (buffer, input, inputsize);
2006 l = inputsize;
2007 }
2008 else {
2009 l = junk_iconv (input, (int)inputsize, buffer, (int)buffersize, UTF8_STR, "cp1252");
2010 if (l <= 0) {
2011 l = junk_iconv (input, (int)inputsize, buffer+2, (int)buffersize - 2, UTF8_STR, "UCS-2LE");
2012 if (l <= 0) {
2013 trace ("failed to encode to ucs2 or cp1252\n");
2014 free (input);
2015 free (buffer);
2016 return NULL;
2017 }
2018 else {
2019 enc = 1;
2020 buffer[0] = 0xff;
2021 buffer[1] = 0xfe;
2022 l += 2;
2023 }
2024 }
2025 }
2026
2027 free (input);
2028
2029 trace ("calculated frame size = %d\n", l + 4);
2030 DB_id3v2_frame_t *f = malloc (l + 4 + sizeof (DB_id3v2_frame_t));
2031 memset (f, 0, sizeof (DB_id3v2_frame_t));
2032 strcpy (f->id, "COMM");
2033 // flags are all zero
2034 f->size = l + 4;
2035 f->data[0] = enc; // encoding=utf8
2036 memcpy (&f->data[1], lang, 3);
2037 memcpy (&f->data[4], buffer, l);
2038
2039 free (buffer);
2040
2041 // append to tag
2042 DB_id3v2_frame_t *tail;
2043 for (tail = tag->frames; tail && tail->next; tail = tail->next);
2044 if (tail) {
2045 tail->next = f;
2046 }
2047 else {
2048 tag->frames = f;
2049 }
2050
2051 return f;
2052 }
2053
2054 int
junk_id3v2_remove_txxx_frame(DB_id3v2_tag_t * tag,const char * key)2055 junk_id3v2_remove_txxx_frame (DB_id3v2_tag_t *tag, const char *key) {
2056 DB_id3v2_frame_t *prev = NULL;
2057 for (DB_id3v2_frame_t *f = tag->frames; f; ) {
2058 DB_id3v2_frame_t *next = f->next;
2059 if (!strcmp (f->id, "TXXX")) {
2060 char *txx = convstr_id3v2 (tag->version[0], f->data[0], f->data+1, f->size-1);
2061 if (txx && !strncasecmp (txx, key, strlen (key))) {
2062 if (prev) {
2063 prev->next = f->next;
2064 }
2065 else {
2066 tag->frames = f->next;
2067 }
2068 free (f);
2069 }
2070 if (txx) {
2071 free (txx);
2072 }
2073 }
2074 else {
2075 prev = f;
2076 }
2077 f = next;
2078 }
2079 return 0;
2080 }
2081
2082 int
junk_id3v2_remove_all_txxx_frames(DB_id3v2_tag_t * tag)2083 junk_id3v2_remove_all_txxx_frames (DB_id3v2_tag_t *tag) {
2084 DB_id3v2_frame_t *prev = NULL;
2085 for (DB_id3v2_frame_t *f = tag->frames; f; ) {
2086 DB_id3v2_frame_t *next = f->next;
2087 if (!strcmp (f->id, "TXXX")) {
2088 if (prev) {
2089 prev->next = f->next;
2090 }
2091 else {
2092 tag->frames = f->next;
2093 }
2094 free (f);
2095 }
2096 else {
2097 prev = f;
2098 }
2099 f = next;
2100 }
2101 return 0;
2102 }
2103
2104 DB_id3v2_frame_t *
junk_id3v2_add_txxx_frame(DB_id3v2_tag_t * tag,const char * key,const char * value)2105 junk_id3v2_add_txxx_frame (DB_id3v2_tag_t *tag, const char *key, const char *value) {
2106 size_t keylen = strlen (key);
2107 size_t valuelen = strlen (value);
2108 size_t len = keylen + valuelen + 1;
2109 uint8_t buffer[len];
2110 memcpy (buffer, key, keylen);
2111 buffer[keylen] = 0;
2112 memcpy (buffer+keylen+1, value, valuelen);
2113
2114 size_t outsize = (keylen + valuelen) * 4 + 1;
2115 uint8_t *out = malloc (outsize);
2116 int encoding = 0;
2117
2118
2119 size_t res;
2120
2121 if (tag->version[0] == 4) {
2122 res = len;
2123 encoding = 3;
2124 memcpy (out, key, keylen);
2125 out[keylen] = 0;
2126 memcpy (out + keylen + 1, value, valuelen);
2127 }
2128 else { // version 3
2129 res = junk_iconv (buffer, len, out, outsize, UTF8_STR, "iso8859-1");
2130 if (res == -1) {
2131 res = junk_iconv (buffer, len, out+2, outsize - 2, UTF8_STR, "UCS-2LE");
2132 if (res == -1) {
2133 return NULL;
2134 }
2135 out[0] = 0xff;
2136 out[1] = 0xfe;
2137 res += 2;
2138 trace ("successfully converted to ucs-2le (size=%d, bom: %x %x)\n", res, out[0], out[1]);
2139 encoding = 1;
2140 }
2141 else {
2142 trace ("successfully converted to cp1252 (size=%d)\n", res);
2143 }
2144 }
2145
2146 // make a frame
2147 int size = res + 1;
2148 trace ("calculated frame size = %d\n", size);
2149 DB_id3v2_frame_t *f = malloc (size + sizeof (DB_id3v2_frame_t));
2150 memset (f, 0, sizeof (DB_id3v2_frame_t));
2151 strcpy (f->id, "TXXX");
2152 f->size = size;
2153 f->data[0] = encoding;
2154 memcpy (&f->data[1], out, res);
2155 // append to tag
2156 DB_id3v2_frame_t *tail;
2157 for (tail = tag->frames; tail && tail->next; tail = tail->next);
2158 if (tail) {
2159 tail->next = f;
2160 }
2161 else {
2162 tag->frames = f;
2163 }
2164
2165 free (out);
2166
2167 return f;
2168 }
2169
2170 // TODO: some non-Txxx frames might still need charset conversion
2171 // TODO: 2.4 TDTG frame (tagging time) should not be converted, but might be useful to create it
2172 int
junk_id3v2_convert_24_to_23(DB_id3v2_tag_t * tag24,DB_id3v2_tag_t * tag23)2173 junk_id3v2_convert_24_to_23 (DB_id3v2_tag_t *tag24, DB_id3v2_tag_t *tag23) {
2174 DB_id3v2_frame_t *f24;
2175 DB_id3v2_frame_t *tail = tag23->frames;
2176 assert (tag24->version[0] == 4);
2177 tag23->version[0] = 3;
2178 tag23->version[1] = 0;
2179
2180 while (tail && tail->next) {
2181 tail = tail->next;
2182 }
2183
2184 const char *copy_frames[] = {
2185 "AENC", "APIC",
2186 "COMR", "ENCR",
2187 "ETCO", "GEOB", "GRID",
2188 "LINK", "MCDI", "MLLT", "OWNE", "PRIV",
2189 "POPM", "POSS", "RBUF",
2190 "RVRB",
2191 "SYLT", "SYTC",
2192 "UFID", "USER", "USLT",
2193 NULL
2194 };
2195
2196 // NOTE: 2.4 ASPI, EQU2, RVA2, SEEK, SIGN are discarded for 2.3
2197 // NOTE: 2.4 PCNT is discarded because it is useless
2198 // NOTE: all Wxxx frames are copy_frames, handled as special case
2199
2200
2201 // "TDRC" TDAT with conversion from ID3v2-strct timestamp to DDMM format
2202 // "TDOR" TORY with conversion from ID3v2-strct timestamp to year
2203 // TODO: "TIPL" IPLS with conversion to non-text format
2204
2205 const char *text_frames[] = {
2206 "TALB", "TBPM", "TCOM", "TCON", "TCOP", "TDLY", "TENC", "TEXT", "TFLT", "TIT1", "TIT2", "TIT3", "TKEY", "TLAN", "TLEN", "TMED", "TOAL", "TOFN", "TOLY", "TOPE", "TOWN", "TPE1", "TPE2", "TPE3", "TPE4", "TPOS", "TPUB", "TRCK", "TRSN", "TRSO", "TSRC", "TSSE", "TXXX", "TDRC", NULL
2207 };
2208
2209 // NOTE: 2.4 TMCL (musician credits list) is discarded for 2.3
2210 // NOTE: 2.4 TMOO (mood) is discarded for 2.3
2211 // NOTE: 2.4 TPRO (produced notice) is discarded for 2.3
2212 // NOTE: 2.4 TSOA (album sort order) is discarded for 2.3
2213 // NOTE: 2.4 TSOP (performer sort order) is discarded for 2.3
2214 // NOTE: 2.4 TSOT (title sort order) is discarded for 2.3
2215 // NOTE: 2.4 TSST (set subtitle) is discarded for 2.3
2216
2217 for (f24 = tag24->frames; f24; f24 = f24->next) {
2218 DB_id3v2_frame_t *f23 = NULL;
2219 // we are altering the tag, so check for tag alter preservation
2220 if (tag24->flags & (1<<6)) {
2221 continue; // discard the frame
2222 }
2223
2224 int simplecopy = 0; // means format is the same in 2.3 and 2.4
2225 int text = 0; // means this is a text frame
2226
2227 int i;
2228
2229 if (f24->id[0] == 'W') { // covers all W000..WZZZ tags
2230 simplecopy = 1;
2231 }
2232
2233 if (!simplecopy) {
2234 for (i = 0; copy_frames[i]; i++) {
2235 if (!strcmp (f24->id, copy_frames[i])) {
2236 simplecopy = 1;
2237 break;
2238 }
2239 }
2240 }
2241
2242 if (!simplecopy) {
2243 // check if this is a text frame
2244 for (i = 0; text_frames[i]; i++) {
2245 if (!strcmp (f24->id, text_frames[i])) {
2246 text = 1;
2247 break;
2248 }
2249 }
2250 }
2251
2252
2253 if (!simplecopy && !text) {
2254 if (!strcmp (f24->id, "COMM")) {
2255 uint8_t enc = f24->data[0];
2256 char lang[4] = {f24->data[1], f24->data[2], f24->data[3], 0};
2257 trace ("COMM enc is: %d\n", (int)enc);
2258 trace ("COMM language is: %s\n", lang);
2259
2260 char *descr = convstr_id3v2 (4, enc, f24->data+4, f24->size-4);
2261 if (!descr) {
2262 trace ("failed to decode COMM frame, probably wrong encoding (%d)\n", enc);
2263 }
2264 else {
2265 // find value
2266 char *value = descr;
2267 while (*value && *value != '\n') {
2268 value++;
2269 }
2270 if (*value != '\n') {
2271 trace ("failed to parse COMM frame, descr was \"%s\"\n", descr);
2272 }
2273 else {
2274 *value = 0;
2275 value++;
2276 f23 = junk_id3v2_add_comment_frame (tag23, lang, descr, value);
2277 if (f23) {
2278 tail = f23;
2279 f23 = NULL;
2280 }
2281 }
2282 free (descr);
2283 }
2284 }
2285 continue; // unknown frame
2286 }
2287
2288 // convert flags
2289 uint8_t flags[2];
2290 // 1st byte (status flags) is the same, but shifted by 1 bit to the left
2291 flags[0] = f24->flags[0] << 1;
2292
2293 // 2nd byte (format flags) is quite different
2294 // 2.4 format is %0h00kmnp (6:grouping, 3:compression, 2:encryption, 1:unsync, 0:datalen)
2295 // 2.3 format is %ijk00000 (7:compression, 6:encryption, 5:grouping)
2296 flags[1] = 0;
2297 if (f24->flags[1] & (1 << 6)) {
2298 flags[1] |= (1 << 5);
2299 }
2300 if (f24->flags[1] & (1 << 3)) {
2301 flags[1] |= (1 << 7);
2302 }
2303 if (f24->flags[1] & (1 << 2)) {
2304 flags[1] |= (1 << 6);
2305 }
2306 if (f24->flags[1] & (1 << 1)) {
2307 // 2.3 doesn't support per-frame unsyncronyzation
2308 }
2309 if (f24->flags[1] & (1 << 0)) {
2310 // 2.3 doesn't support data length, but remember to skip 4 bytes of
2311 // the frame
2312 }
2313
2314 if (simplecopy) {
2315 f23 = malloc (sizeof (DB_id3v2_frame_t) + f24->size);
2316 memset (f23, 0, sizeof (DB_id3v2_frame_t) + f24->size);
2317 strcpy (f23->id, f24->id);
2318 if (f24->flags[1] & (1<<0)) {
2319 // skip 1st 4 bytes (2.4 data length indicator)
2320 memcpy (f23->data, f24->data+4, f24->size-4);
2321 f23->size = f24->size-4;
2322 }
2323 else {
2324 f23->size = f24->size;
2325 memcpy (f23->data, f24->data, f24->size);
2326 }
2327 f23->flags[0] = flags[0];
2328 f23->flags[1] = flags[1];
2329 }
2330 else if (text) {
2331
2332 char *decoded = convstr_id3v2 (4, f24->data[0], f24->data+1, f24->size-1);
2333 if (!decoded) {
2334 trace ("junk_id3v2_convert_24_to_23: failed to decode text frame %s\n", f24->id);
2335 continue; // failed, discard it
2336 }
2337 if (!strcmp (f24->id, "TDRC")) {
2338 trace ("junk_id3v2_convert_24_to_23: TDRC text: %s\n", decoded);
2339 int year, month, day;
2340 int c = sscanf (decoded, "%4d-%2d-%2d", &year, &month, &day);
2341 if (c >= 1) {
2342 char s[5];
2343 snprintf (s, sizeof (s), "%04d", year);
2344 f23 = junk_id3v2_add_text_frame (tag23, "TYER", s);
2345 if (f23) {
2346 tail = f23;
2347 f23 = NULL;
2348 }
2349 }
2350 if (c == 3) {
2351 char s[5];
2352 snprintf (s, sizeof (s), "%02d%02d", month, day);
2353 f23 = junk_id3v2_add_text_frame (tag23, "TDAT", s);
2354 if (f23) {
2355 tail = f23;
2356 f23 = NULL;
2357 }
2358 }
2359 else {
2360 trace ("junk_id3v2_add_text_frame: 2.4 TDRC doesn't have month/day info; discarded\n");
2361 }
2362 }
2363 else if (!strcmp (f24->id, "TDOR")) {
2364 trace ("junk_id3v2_convert_24_to_23: TDOR text: %s\n", decoded);
2365 int year;
2366 int c = sscanf (decoded, "%4d", &year);
2367 if (c == 1) {
2368 char s[5];
2369 snprintf (s, sizeof (s), "%04d", year);
2370 f23 = junk_id3v2_add_text_frame (tag23, "TORY", s);
2371 if (f23) {
2372 tail = f23;
2373 f23 = NULL;
2374 }
2375 }
2376 else {
2377 trace ("junk_id3v2_add_text_frame: 2.4 TDOR doesn't have month/day info; discarded\n");
2378 }
2379 }
2380 else {
2381 // encode for 2.3
2382 f23 = junk_id3v2_add_text_frame (tag23, f24->id, decoded);
2383 if (f23) {
2384 tail = f23;
2385 f23 = NULL;
2386 }
2387 }
2388 free (decoded);
2389 }
2390 if (f23) {
2391 if (tail) {
2392 tail->next = f23;
2393 }
2394 else {
2395 tag23->frames = f23;
2396 }
2397 tail = f23;
2398 }
2399 }
2400
2401 // convert tag header
2402 tag23->flags = tag24->flags;
2403 tag23->flags &= ~(1<<4); // no footer (unsupported in 2.3)
2404 tag23->flags &= ~(1<<7); // no unsync
2405
2406 return 0;
2407 }
2408
2409 int
junk_id3v2_convert_23_to_24(DB_id3v2_tag_t * tag23,DB_id3v2_tag_t * tag24)2410 junk_id3v2_convert_23_to_24 (DB_id3v2_tag_t *tag23, DB_id3v2_tag_t *tag24) {
2411 DB_id3v2_frame_t *f23;
2412 DB_id3v2_frame_t *tail = tag24->frames;
2413
2414 while (tail && tail->next) {
2415 tail = tail->next;
2416 }
2417
2418 const char *copy_frames[] = {
2419 "AENC", "APIC",
2420 "COMM", "COMR", "ENCR",
2421 "ETCO", "GEOB", "GRID",
2422 "LINK", "MCDI", "MLLT", "OWNE", "PRIV",
2423 "POPM", "POSS", "RBUF",
2424 "RVRB",
2425 "SYLT", "SYTC",
2426 "UFID", "USER", "USLT",
2427 NULL
2428 };
2429
2430 // NOTE: all Wxxx frames are copy_frames, handled as special case
2431
2432 // "TDRC" TDAT with conversion from ID3v2-strct timestamp to DDMM format
2433 // "TDOR" TORY with conversion from ID3v2-strct timestamp to year
2434 // TODO: "TIPL" IPLS with conversion to non-text format
2435
2436 const char *text_frames[] = {
2437 "TALB", "TBPM", "TCOM", "TCON", "TCOP", "TDLY", "TENC", "TEXT", "TFLT", "TIT1", "TIT2", "TIT3", "TKEY", "TLAN", "TLEN", "TMED", "TOAL", "TOFN", "TOLY", "TOPE", "TOWN", "TPE1", "TPE2", "TPE3", "TPE4", "TPOS", "TPUB", "TRCK", "TRSN", "TRSO", "TSRC", "TSSE", "TXXX", "TDRC", NULL
2438 };
2439
2440 for (f23 = tag23->frames; f23; f23 = f23->next) {
2441 // we are altering the tag, so check for tag alter preservation
2442 if (tag23->flags & (1<<7)) {
2443 continue; // discard the frame
2444 }
2445
2446 int simplecopy = 0; // means format is the same in 2.3 and 2.4
2447 int text = 0; // means this is a text frame
2448
2449 int i;
2450
2451 if (f23->id[0] == 'W') { // covers all W000..WZZZ tags
2452 simplecopy = 1;
2453 }
2454
2455 if (!simplecopy) {
2456 for (i = 0; copy_frames[i]; i++) {
2457 if (!strcmp (f23->id, copy_frames[i])) {
2458 simplecopy = 1;
2459 break;
2460 }
2461 }
2462 }
2463
2464 if (!simplecopy) {
2465 // check if this is a text frame
2466 for (i = 0; text_frames[i]; i++) {
2467 if (!strcmp (f23->id, text_frames[i])) {
2468 text = 1;
2469 break;
2470 }
2471 }
2472 }
2473
2474
2475 if (!simplecopy && !text) {
2476 continue; // unknown frame
2477 }
2478
2479 // convert flags
2480 uint8_t flags[2];
2481 // 1st byte (status flags) is the same, but shifted by 1 bit to the
2482 // right
2483 flags[0] = f23->flags[0] >> 1;
2484
2485 // 2nd byte (format flags) is quite different
2486 // 2.4 format is %0h00kmnp (6:grouping, 3:compression, 2:encryption, 1:unsync, 0:datalen)
2487 // 2.3 format is %ijk00000 (7:compression, 6:encryption, 5:grouping)
2488 flags[1] = 0;
2489 if (f23->flags[1] & (1 << 7)) {
2490 flags[1] |= (1 << 3);
2491 }
2492 if (f23->flags[1] & (1 << 6)) {
2493 flags[1] |= (1 << 2);
2494 }
2495 if (f23->flags[1] & (1 << 5)) {
2496 flags[1] |= (1 << 6);
2497 }
2498
2499 DB_id3v2_frame_t *f24 = NULL;
2500 if (simplecopy) {
2501 f24 = malloc (sizeof (DB_id3v2_frame_t) + f23->size);
2502 memset (f24, 0, sizeof (DB_id3v2_frame_t) + f23->size);
2503 strcpy (f24->id, f23->id);
2504 f24->size = f23->size;
2505 memcpy (f24->data, f23->data, f23->size);
2506 f24->flags[0] = flags[0];
2507 f24->flags[1] = flags[1];
2508 }
2509 else if (text) {
2510 // decode text into utf8
2511 char *decoded = convstr_id3v2 (3, f23->data[0], f23->data+1, f23->size-1);
2512 if (!decoded) {
2513 trace ("junk_id3v2_convert_23_to_24: failed to decode text frame %s\n", f23->id);
2514 continue; // failed, discard it
2515 }
2516 if (!strcmp (f23->id, "TDRC")) {
2517 trace ("junk_id3v2_convert_23_to_24: TDRC text: %s\n", decoded);
2518 int year, month, day;
2519 int c = sscanf (decoded, "%4d-%2d-%2d", &year, &month, &day);
2520 if (c >= 1) {
2521 char s[5];
2522 snprintf (s, sizeof (s), "%04d", year);
2523 f24 = junk_id3v2_add_text_frame (tag24, "TYER", s);
2524 if (f24) {
2525 tail = f24;
2526 f24 = NULL;
2527 }
2528 }
2529 if (c == 3) {
2530 char s[5];
2531 snprintf (s, sizeof (s), "%02d%02d", month, day);
2532 f24 = junk_id3v2_add_text_frame (tag24, "TDAT", s);
2533 if (f24) {
2534 tail = f24;
2535 f24 = NULL;
2536 }
2537 }
2538 else {
2539 trace ("junk_id3v2_add_text_frame: 2.4 TDRC doesn't have month/day info; discarded\n");
2540 }
2541 }
2542 else if (!strcmp (f23->id, "TORY")) {
2543 trace ("junk_id3v2_convert_23_to_24: TDOR text: %s\n", decoded);
2544 int year;
2545 int c = sscanf (decoded, "%4d", &year);
2546 if (c == 1) {
2547 char s[5];
2548 snprintf (s, sizeof (s), "%04d", year);
2549 f24 = junk_id3v2_add_text_frame (tag24, "TDOR", s);
2550 if (f24) {
2551 tail = f24;
2552 f24 = NULL;
2553 }
2554 }
2555 else {
2556 trace ("junk_id3v2_add_text_frame: 2.4 TDOR doesn't have month/day info; discarded\n");
2557 }
2558 }
2559 else {
2560 // encode for 2.4
2561 f24 = junk_id3v2_add_text_frame (tag24, f23->id, decoded);
2562 if (f24) {
2563 tail = f24;
2564 f24 = NULL;
2565 }
2566 }
2567 free (decoded);
2568 }
2569 if (f24) {
2570 if (tail) {
2571 tail->next = f24;
2572 }
2573 else {
2574 tag24->frames = f24;
2575 }
2576 tail = f24;
2577 }
2578 }
2579
2580 // convert tag header
2581 tag24->version[0] = 4;
2582 tag24->version[1] = 0;
2583 tag24->flags = tag23->flags;
2584 tag24->flags &= ~(1<<4); // no footer (unsupported in 2.3)
2585 tag24->flags &= ~(1<<7); // no unsync
2586
2587 return 0;
2588 }
2589
2590 int
junk_id3v2_convert_22_to_24(DB_id3v2_tag_t * tag22,DB_id3v2_tag_t * tag24)2591 junk_id3v2_convert_22_to_24 (DB_id3v2_tag_t *tag22, DB_id3v2_tag_t *tag24) {
2592 DB_id3v2_frame_t *f22;
2593 DB_id3v2_frame_t *tail = tag24->frames;
2594
2595 while (tail && tail->next) {
2596 tail = tail->next;
2597 }
2598
2599 const char *copy_frames[] = {
2600 "BUF", "COM", "CRA", "ETC", "GEO", "IPL", "MCI", "MLL", "POP", "REV", "SLT", "STC", "UFI", "ULT",
2601 NULL
2602 };
2603
2604 const char *copy_frames_24[] = {
2605 "RBUF", "COMM", "AENC", "ETCO", "GEOB", "TIPL", "MCDI", "MLLT", "POPM", "RVRB", "SYLT", "SYTC", "UFID", "USLT",
2606 NULL
2607 };
2608
2609 // NOTE: BUF is discarded (no match in 2.4)
2610 // NOTE: CNT is discarded (useless)
2611 // NOTE: CRM is discarded (no match in 2.4)
2612 // NOTE: EQU is discarded (difficult to convert to EQU2)
2613 // NOTE: LNK is discarded (maybe later)
2614 // NOTE: PIC is discarded (needs conversion from custom image-format field to mime-type)
2615 // NOTE: RVA is discarded (subjective, and difficult to convert to RVA2)
2616
2617 const char *text_frames[] = {
2618 "TAL", "TBP", "TCM", "TCO", "TCR", "TDY", "TEN", "TFT", "TKE", "TLA", "TLE", "TMT", "TOA", "TOF", "TOL", "TOT", "TP1", "TP2", "TP3", "TP4", "TPA", "TPB", "TRC", "TRK", "TSS", "TT1", "TT2", "TT3", "TXT", "TXX", "TOR", NULL
2619 };
2620
2621 const char *text_frames_24[] = {
2622 "TALB", "TBPM", "TCOM", "TCON", "TCOP", "TDLY", "TENC", "TFLT", "TKEY", "TLAN", "TLEN", "TMED", "TOPE", "TOFN", "TOLY", "TOAL", "TPE1", "TPE2", "TPE3", "TPE4", "TPOS", "TPUB", "TSRC", "TRCK", "TSSE", "TIT1", "TIT2", "TIT3", "TEXT", "TXXX", "TDOR"
2623 };
2624
2625 // NOTE: TRD is discarded (no match in 2.4)
2626 // NOTE: TSI is discarded (no match in 2.4)
2627
2628 int year = 0;
2629 int month = 0;
2630 int day = 0;
2631 int hour = 0;
2632 int minute = 0;
2633
2634 for (f22 = tag22->frames; f22; f22 = f22->next) {
2635 int simplecopy = -1; // means format is the same in 2.2 and 2.4
2636 int text = -1; // means this is a text frame
2637
2638 int i;
2639
2640 if (f22->id[0] == 'W') { // covers all W00..WZZ tags
2641 simplecopy = 0;
2642 }
2643
2644 if (simplecopy == -1) {
2645 for (i = 0; copy_frames[i]; i++) {
2646 if (!strcmp (f22->id, copy_frames[i])) {
2647 simplecopy = i;
2648 break;
2649 }
2650 }
2651 }
2652
2653 if (simplecopy == -1) {
2654 // check if this is a text frame
2655 for (i = 0; text_frames[i]; i++) {
2656 if (!strcmp (f22->id, text_frames[i])) {
2657 text = i;
2658 break;
2659 }
2660 }
2661 }
2662
2663
2664 if (simplecopy == -1 && text == -1) {
2665 continue; // unknown frame
2666 }
2667
2668 // convert flags
2669 uint8_t flags[2];
2670 // 1st byte (status flags) is the same, but shifted by 1 bit to the
2671 // right
2672 flags[0] = f22->flags[0] >> 1;
2673
2674 // 2nd byte (format flags) is quite different
2675 // 2.4 format is %0h00kmnp (grouping, compression, encryption, unsync)
2676 // 2.3 format is %ijk00000 (compression, encryption, grouping)
2677 flags[1] = 0;
2678 if (f22->flags[1] & (1 << 4)) {
2679 flags[1] |= (1 << 6);
2680 }
2681 if (f22->flags[1] & (1 << 7)) {
2682 flags[1] |= (1 << 3);
2683 }
2684 if (f22->flags[1] & (1 << 6)) {
2685 flags[1] |= (1 << 2);
2686 }
2687 if (f22->flags[1] & (1 << 5)) {
2688 flags[1] |= (1 << 1);
2689 }
2690
2691 DB_id3v2_frame_t *f24 = NULL;
2692 if (simplecopy != -1) {
2693 f24 = malloc (sizeof (DB_id3v2_frame_t) + f22->size);
2694 memset (f24, 0, sizeof (DB_id3v2_frame_t) + f22->size);
2695 if (f22->id[0] == 'W') { // duplicate last letter of W00-WZZ frames
2696 strcpy (f24->id, f22->id);
2697 f24->id[3] = f24->id[2];
2698 f24->id[4] = 0;
2699 }
2700 else {
2701 strcpy (f24->id, copy_frames_24[simplecopy]);
2702 }
2703 f24->size = f22->size;
2704 memcpy (f24->data, f22->data, f22->size);
2705 f24->flags[0] = flags[0];
2706 f24->flags[1] = flags[1];
2707 }
2708 else if (text != -1) {
2709 // decode text into utf8
2710 char *decoded = convstr_id3v2 (2, f22->data[0], f22->data+1, f22->size-1);
2711 if (!decoded) {
2712 trace ("junk_id3v2_convert_23_to_24: failed to decode text frame %s\n", f22->id);
2713 continue; // failed, discard it
2714 }
2715 // encode for 2.4
2716 f24 = junk_id3v2_add_text_frame (tag24, text_frames_24[text], decoded);
2717 if (f24) {
2718 tail = f24;
2719 f24 = NULL;
2720 }
2721 free (decoded);
2722 }
2723 else if (!strcmp (f22->id, "TYE")) {
2724 char *decoded = convstr_id3v2 (2, f22->data[0], f22->data+1, f22->size-1);
2725 if (decoded) {
2726 year = atoi (decoded);
2727 free (decoded);
2728 }
2729 }
2730 else if (!strcmp (f22->id, "TDA")) {
2731 char *decoded = convstr_id3v2 (2, f22->data[0], f22->data+1, f22->size-1);
2732 if (decoded) {
2733 sscanf (decoded, "%02d%02d", &month, &day);
2734 free (decoded);
2735 }
2736 }
2737 else if (!strcmp (f22->id, "TIM")) {
2738 char *decoded = convstr_id3v2 (2, f22->data[0], f22->data+1, f22->size-1);
2739 if (decoded) {
2740 sscanf (decoded, "%02d%02d", &hour, &minute);
2741 free (decoded);
2742 }
2743 }
2744 if (f24) {
2745 if (tail) {
2746 tail->next = f24;
2747 }
2748 else {
2749 tag24->frames = f24;
2750 }
2751 tail = f24;
2752 }
2753 }
2754
2755 char tdrc[100];
2756 char *p = tdrc;
2757 if (year > 0) {
2758 int n = sprintf (p, "%04d", year);
2759 p += n;
2760 if (month) {
2761 n = sprintf (p, "-%02d", month);
2762 p += n;
2763 if (day) {
2764 n = sprintf (p, "-%02d", day);
2765 p += n;
2766 if (hour && minute) {
2767 n = sprintf (p, "-T%02d:%02d", hour, minute);
2768 p += n;
2769 }
2770 }
2771 }
2772 DB_id3v2_frame_t *f24 = junk_id3v2_add_text_frame (tag24, "TDRC", tdrc);
2773 if (f24) {
2774 tail = f24;
2775 }
2776 }
2777
2778 // convert tag header
2779 tag24->version[0] = 4;
2780 tag24->version[1] = 0;
2781 tag24->flags = tag22->flags;
2782 tag24->flags &= ~(1<<4); // no footer (unsupported in 2.3)
2783 tag24->flags &= ~(1<<7); // no unsync
2784
2785 return 0;
2786 }
2787
2788 int
junk_apev2_remove_frames(DB_apev2_tag_t * tag,const char * frame_id)2789 junk_apev2_remove_frames (DB_apev2_tag_t *tag, const char *frame_id) {
2790 DB_apev2_frame_t *prev = NULL;
2791 for (DB_apev2_frame_t *f = tag->frames; f; ) {
2792 DB_apev2_frame_t *next = f->next;
2793 if (!strcasecmp (f->key, frame_id)) {
2794 if (prev) {
2795 prev->next = f->next;
2796 }
2797 else {
2798 tag->frames = f->next;
2799 }
2800 free (f);
2801 }
2802 else {
2803 prev = f;
2804 }
2805 f = next;
2806 }
2807 return 0;
2808 }
2809
2810 int
junk_apev2_remove_all_text_frames(DB_apev2_tag_t * tag)2811 junk_apev2_remove_all_text_frames (DB_apev2_tag_t *tag) {
2812 DB_apev2_frame_t *prev = NULL;
2813 for (DB_apev2_frame_t *f = tag->frames; f; ) {
2814 DB_apev2_frame_t *next = f->next;
2815 int valuetype = ((f->flags >> 1) & 3);
2816 if (valuetype == 0) {
2817 if (prev) {
2818 prev->next = f->next;
2819 }
2820 else {
2821 tag->frames = f->next;
2822 }
2823 free (f);
2824 }
2825 else {
2826 prev = f;
2827 }
2828 f = next;
2829 }
2830 return 0;
2831 }
2832 DB_apev2_frame_t *
junk_apev2_add_text_frame(DB_apev2_tag_t * tag,const char * frame_id,const char * value)2833 junk_apev2_add_text_frame (DB_apev2_tag_t *tag, const char *frame_id, const char *value) {
2834 trace ("adding apev2 frame %s %s\n", frame_id, value);
2835 if (!*value) {
2836 return NULL;
2837 }
2838 DB_apev2_frame_t *tail = tag->frames;
2839 while (tail && tail->next) {
2840 tail = tail->next;
2841 }
2842
2843 #if 0 // this will split every line into separate field
2844 const char *next = value;
2845 while (*value) {
2846 while (*next && *next != '\n') {
2847 next++;
2848 }
2849
2850 //int size = strlen (value);
2851 int size = next - value;
2852 if (*next) {
2853 next++;
2854 }
2855
2856 if (!size) {
2857 continue;
2858 }
2859
2860 trace ("adding apev2 subframe %s len %d\n", value, size);
2861 DB_apev2_frame_t *f = malloc (sizeof (DB_apev2_frame_t) + size);
2862 if (!f) {
2863 trace ("junk_apev2_add_text_frame: failed to allocate %d bytes\n", size);
2864 return NULL;
2865 }
2866 memset (f, 0, sizeof (DB_apev2_frame_t));
2867 f->flags = 0;
2868 strcpy (f->key, frame_id);
2869 f->size = size;
2870 memcpy (f->data, value, size);
2871
2872 if (tail) {
2873 tail->next = f;
2874 }
2875 else {
2876 tag->frames = f;
2877 }
2878 tail = f;
2879
2880 value = next;
2881 }
2882 #endif
2883 size_t size = strlen (value);
2884 DB_apev2_frame_t *f = malloc (sizeof (DB_apev2_frame_t) + size);
2885 if (!f) {
2886 trace ("junk_apev2_add_text_frame: failed to allocate %d bytes\n", size);
2887 return NULL;
2888 }
2889 memset (f, 0, sizeof (DB_apev2_frame_t));
2890 f->flags = 0;
2891 strcpy (f->key, frame_id);
2892 f->size = size;
2893 memcpy (f->data, value, size);
2894
2895 if (tail) {
2896 tail->next = f;
2897 }
2898 else {
2899 tag->frames = f;
2900 }
2901 tail = f;
2902 return tail;
2903 }
2904
2905 int
junk_id3v2_convert_apev2_to_24(DB_apev2_tag_t * ape,DB_id3v2_tag_t * tag24)2906 junk_id3v2_convert_apev2_to_24 (DB_apev2_tag_t *ape, DB_id3v2_tag_t *tag24) {
2907 DB_apev2_frame_t *f_ape;
2908 DB_id3v2_frame_t *tail = tag24->frames;
2909
2910 while (tail && tail->next) {
2911 tail = tail->next;
2912 }
2913
2914 const char *text_keys[] = {
2915 "Title", "Subtitle", "Artist", "Album", "Publisher", "Conductor", "Track", "Composer", "Copyright", "Genre", "Disc", "ISRC", "Language", "Year", NULL
2916 };
2917
2918 const char *text_keys_24[] = {
2919 "TIT2", "TIT3", "TPE1", "TALB", "TPUB", "TPE3", "TRCK", "TCOM", "TCOP", "TCON", "TPOS", "TSRC", "TLAN", "TDRC"
2920 };
2921
2922 const char *comm_frames[] = {
2923 "Comment", "EAN/UPC", "ISBN", "Catalog", "LC", "Publicationright", "Record Location", "Related", "Abstract", "Bibliography", NULL
2924 };
2925
2926 // FIXME: additional frames: File->WOAF
2927 // converted to COMM: Comment, EAN/UPC, ISBN, Catalog, LC, Publicationright, Record Location, Related, Abstract, Bibliography
2928 // "Debut album" is discarded
2929 // "Index" is discarded
2930 // "Introplay" is discarded
2931
2932 for (f_ape = ape->frames; f_ape; f_ape = f_ape->next) {
2933 int i;
2934
2935 for (i = 0; text_keys[i]; i++) {
2936 if (!strcasecmp (text_keys[i], f_ape->key)) {
2937 break;
2938 }
2939 }
2940
2941 DB_id3v2_frame_t *f24 = NULL;
2942
2943 if (text_keys[i]) {
2944 char str[f_ape->size+1];
2945 memcpy (str, f_ape->data, f_ape->size);
2946 str[f_ape->size] = 0;
2947 f24 = junk_id3v2_add_text_frame (tag24, text_keys_24[i], str);
2948 if (f24) {
2949 tail = f24;
2950 f24 = NULL;
2951 }
2952 }
2953 else {
2954 for (i = 0; comm_frames[i]; i++) {
2955 if (!strcasecmp (f_ape->key, comm_frames[i])) {
2956 char str[f_ape->size+1];
2957 memcpy (str, f_ape->data, f_ape->size);
2958 str[f_ape->size] = 0;
2959 if (!strcasecmp (f_ape->key, "Comment")) {
2960 junk_id3v2_add_comment_frame (tag24, "eng", "", str);
2961 }
2962 else {
2963 junk_id3v2_add_comment_frame (tag24, "eng", comm_frames[i], str);
2964 }
2965 break;
2966 }
2967 }
2968 }
2969
2970 if (f24) {
2971 if (tail) {
2972 tail->next = f24;
2973 }
2974 else {
2975 tag24->frames = f24;
2976 }
2977 tail = f24;
2978 }
2979 }
2980
2981 // convert tag header
2982 tag24->version[0] = 4;
2983 tag24->version[1] = 0;
2984 tag24->flags = 0;
2985
2986 return 0;
2987 }
2988
2989 int
junk_apev2_write_i32_le2(int fd,uint32_t data)2990 junk_apev2_write_i32_le2 (int fd, uint32_t data) {
2991 int shift = 0;
2992 for (int i = 0; i < 4; i++) {
2993 uint8_t d = (data >> shift) & 0xff;
2994 if (write (fd, &d, 1) != 1) {
2995 return -1;
2996 }
2997 shift += 8;
2998 }
2999
3000 return 0;
3001 }
3002
3003 int
junk_apev2_write_i32_le(FILE * fp,uint32_t data)3004 junk_apev2_write_i32_le (FILE *fp, uint32_t data) {
3005 int shift = 0;
3006 for (int i = 0; i < 4; i++) {
3007 uint8_t d = (data >> shift) & 0xff;
3008 if (fwrite (&d, 1, 1, fp) != 1) {
3009 return -1;
3010 }
3011 shift += 8;
3012 }
3013
3014 return 0;
3015 }
3016
3017 int
junk_apev2_write2(int fd,DB_apev2_tag_t * tag,int write_header,int write_footer)3018 junk_apev2_write2 (int fd, DB_apev2_tag_t *tag, int write_header, int write_footer) {
3019 // calc size and numitems
3020 uint32_t numframes = 0;
3021 uint32_t size = 0;
3022 DB_apev2_frame_t *f = tag->frames;
3023 while (f) {
3024 size += 8 + strlen (f->key) + 1 + f->size;
3025 numframes++;
3026 f = f->next;
3027 }
3028 size += 32;
3029
3030 trace ("junk_apev2_write2: writing apev2 tag, size=%d, numframes=%d\n", size, numframes);
3031
3032
3033 if (write_header) {
3034 if (write (fd, "APETAGEX", 8) != 8) {
3035 trace ("junk_apev2_write2: failed to write apev2 header signature\n");
3036 goto error;
3037 }
3038 uint32_t flags = (1 << 31) | (1 << 29); // contains header, this is header
3039 if (!write_footer) {
3040 flags |= 1 << 30; // contains no footer
3041 }
3042 uint32_t header[4] = {
3043 2000, // version
3044 size,
3045 numframes,
3046 flags
3047 };
3048 for (int i = 0; i < 4; i++) {
3049 if (junk_apev2_write_i32_le2 (fd, header[i]) != 0) {
3050 trace ("junk_apev2_write_i32_le2: failed to write apev2 header\n");
3051 goto error;
3052 }
3053 }
3054 // write 8 bytes of padding
3055 header[0] = header[1] = 0;
3056 if (write (fd, header, 8) != 8) {
3057 trace ("junk_apev2_write2: failed to write apev2 header padding\n");
3058 goto error;
3059 }
3060 }
3061
3062 // write items
3063 f = tag->frames;
3064 while (f) {
3065 if (junk_apev2_write_i32_le2 (fd, f->size) != 0) {
3066 trace ("junk_apev2_write_i32_le2: failed to write apev2 item size\n");
3067 goto error;
3068 }
3069 if (junk_apev2_write_i32_le2 (fd, f->flags) != 0) {
3070 trace ("junk_apev2_write_i32_le2: failed to write apev2 item flags\n");
3071 goto error;
3072 }
3073 int l = strlen (f->key) + 1;
3074 if (write (fd, f->key, l) != l) {
3075 trace ("junk_apev2_write2: failed to write apev2 item key\n");
3076 goto error;
3077 }
3078 if (write (fd, f->data, f->size) != f->size) {
3079 trace ("junk_apev2_write2: failed to write apev2 item value\n");
3080 goto error;
3081 }
3082 f = f->next;
3083 }
3084
3085 if (write_footer) {
3086 if (write (fd, "APETAGEX", 8) != 8) {
3087 trace ("junk_apev2_write: failed to write apev2 footer signature\n");
3088 goto error;
3089 }
3090 uint32_t flags = 0;
3091 if (write_header) {
3092 flags |= 1 << 31;
3093 }
3094 uint32_t header[4] = {
3095 2000, // version
3096 size,
3097 numframes,
3098 flags
3099 };
3100 for (int i = 0; i < 4; i++) {
3101 if (junk_apev2_write_i32_le2 (fd, header[i]) != 0) {
3102 trace ("junk_apev2_write_i32_le2: failed to write apev2 footer\n");
3103 goto error;
3104 }
3105 }
3106 // write 8 bytes of padding
3107 header[0] = header[1] = 0;
3108 if (write (fd, header, 8) != 8) {
3109 trace ("junk_apev2_write2: failed to write apev2 footer padding\n");
3110 goto error;
3111 }
3112 }
3113 return 0;
3114 error:
3115 return -1;
3116 }
3117
3118
3119 int
junk_apev2_write(FILE * fp,DB_apev2_tag_t * tag,int write_header,int write_footer)3120 junk_apev2_write (FILE *fp, DB_apev2_tag_t *tag, int write_header, int write_footer) {
3121 // calc size and numitems
3122 uint32_t numframes = 0;
3123 uint32_t size = 0;
3124 DB_apev2_frame_t *f = tag->frames;
3125 while (f) {
3126 size += 8 + strlen (f->key) + 1 + f->size;
3127 numframes++;
3128 f = f->next;
3129 }
3130 size += 32;
3131
3132 trace ("junk_apev2_write: writing apev2 tag, size=%d, numframes=%d\n", size, numframes);
3133
3134
3135 if (write_header) {
3136 if (fwrite ("APETAGEX", 1, 8, fp) != 8) {
3137 trace ("junk_apev2_write: failed to write apev2 header signature\n");
3138 goto error;
3139 }
3140 uint32_t flags = (1 << 31) | (1 << 29); // contains header, this is header
3141 if (!write_footer) {
3142 flags |= 1 << 30; // contains no footer
3143 }
3144 uint32_t header[4] = {
3145 2000, // version
3146 size,
3147 numframes,
3148 flags
3149 };
3150 for (int i = 0; i < 4; i++) {
3151 if (junk_apev2_write_i32_le (fp, header[i]) != 0) {
3152 trace ("junk_apev2_write_i32_le: failed to write apev2 header\n");
3153 goto error;
3154 }
3155 }
3156 // write 8 bytes of padding
3157 header[0] = header[1] = 0;
3158 if (fwrite (header, 1, 8, fp) != 8) {
3159 trace ("junk_apev2_write_i32_le: failed to write apev2 header padding\n");
3160 goto error;
3161 }
3162 }
3163
3164 // write items
3165 f = tag->frames;
3166 while (f) {
3167 if (junk_apev2_write_i32_le (fp, f->size) != 0) {
3168 trace ("junk_apev2_write_i32_le: failed to write apev2 item size\n");
3169 goto error;
3170 }
3171 if (junk_apev2_write_i32_le (fp, f->flags) != 0) {
3172 trace ("junk_apev2_write_i32_le: failed to write apev2 item flags\n");
3173 goto error;
3174 }
3175 int l = strlen (f->key) + 1;
3176 if (fwrite (f->key, 1, l, fp) != l) {
3177 trace ("junk_apev2_write_i32_le: failed to write apev2 item key\n");
3178 goto error;
3179 }
3180 if (fwrite (f->data, 1, f->size, fp) != f->size) {
3181 trace ("junk_apev2_write_i32_le: failed to write apev2 item value\n");
3182 goto error;
3183 }
3184 f = f->next;
3185 }
3186
3187 if (write_footer) {
3188 if (fwrite ("APETAGEX", 1, 8, fp) != 8) {
3189 trace ("junk_apev2_write: failed to write apev2 footer signature\n");
3190 goto error;
3191 }
3192 uint32_t flags = 0;
3193 if (write_header) {
3194 flags |= 1 << 31;
3195 }
3196 uint32_t header[4] = {
3197 2000, // version
3198 size,
3199 numframes,
3200 flags
3201 };
3202 for (int i = 0; i < 4; i++) {
3203 if (junk_apev2_write_i32_le (fp, header[i]) != 0) {
3204 trace ("junk_apev2_write_i32_le: failed to write apev2 footer\n");
3205 goto error;
3206 }
3207 }
3208 // write 8 bytes of padding
3209 header[0] = header[1] = 0;
3210 if (fwrite (header, 1, 8, fp) != 8) {
3211 trace ("junk_apev2_write_i32_le: failed to write apev2 footer padding\n");
3212 goto error;
3213 }
3214 }
3215 return 0;
3216 error:
3217 return -1;
3218 }
3219
3220 int
junk_id3v2_write2(int out,DB_id3v2_tag_t * tag)3221 junk_id3v2_write2 (int out, DB_id3v2_tag_t *tag) {
3222 if (tag->version[0] < 3) {
3223 fprintf (stderr, "junk_write_id3v2: writing id3v2.2 is not supported\n");
3224 return -1;
3225 }
3226
3227 FILE *fp = NULL;
3228 char *buffer = NULL;
3229 int err = -1;
3230
3231 // write tag header
3232 if (write (out, "ID3", 3) != 3) {
3233 fprintf (stderr, "junk_write_id3v2: failed to write ID3 signature\n");
3234 goto error;
3235 }
3236
3237 if (write (out, tag->version, 2) != 2) {
3238 fprintf (stderr, "junk_write_id3v2: failed to write tag version\n");
3239 goto error;
3240 }
3241 uint8_t flags = tag->flags;
3242 flags &= ~(1<<6); // we don't (yet?) write ext header
3243 flags &= ~(1<<4); // we don't write footer
3244
3245 if (write (out, &flags, 1) != 1) {
3246 fprintf (stderr, "junk_write_id3v2: failed to write tag flags\n");
3247 goto error;
3248 }
3249 // run through list of frames, and calculate size
3250 uint32_t sz = 0;
3251 for (DB_id3v2_frame_t *f = tag->frames; f; f = f->next) {
3252 // each tag has 10 bytes header
3253 if (tag->version[0] > 2) {
3254 sz += 10;
3255 }
3256 else {
3257 sz += 6;
3258 }
3259 sz += f->size;
3260 }
3261
3262 trace ("calculated tag size: %d bytes\n", sz);
3263 uint8_t tagsize[4];
3264 tagsize[0] = (sz >> 21) & 0x7f;
3265 tagsize[1] = (sz >> 14) & 0x7f;
3266 tagsize[2] = (sz >> 7) & 0x7f;
3267 tagsize[3] = sz & 0x7f;
3268 if (write (out, tagsize, 4) != 4) {
3269 fprintf (stderr, "junk_write_id3v2: failed to write tag size\n");
3270 goto error;
3271 }
3272
3273 trace ("writing frames\n");
3274 // write frames
3275 for (DB_id3v2_frame_t *f = tag->frames; f; f = f->next) {
3276 trace ("writing frame %s size %d\n", f->id, f->size);
3277 int id_size = 3;
3278 uint8_t frame_size[4];
3279 if (tag->version[0] > 2) {
3280 id_size = 4;
3281 }
3282 if (tag->version[0] == 3) {
3283 frame_size[0] = (f->size >> 24) & 0xff;
3284 frame_size[1] = (f->size >> 16) & 0xff;
3285 frame_size[2] = (f->size >> 8) & 0xff;
3286 frame_size[3] = f->size & 0xff;
3287 }
3288 else if (tag->version[0] == 4) {
3289 frame_size[0] = (f->size >> 21) & 0x7f;
3290 frame_size[1] = (f->size >> 14) & 0x7f;
3291 frame_size[2] = (f->size >> 7) & 0x7f;
3292 frame_size[3] = f->size & 0x7f;
3293 }
3294 if (write (out, f->id, 4) != 4) {
3295 fprintf (stderr, "junk_write_id3v2: failed to write frame id %s\n", f->id);
3296 goto error;
3297 }
3298 if (write (out, frame_size, 4) != 4) {
3299 fprintf (stderr, "junk_write_id3v2: failed to write frame size, id %s, size %d\n", f->id, f->size);
3300 goto error;
3301 }
3302 if (write (out, f->flags, 2) != 2) {
3303 fprintf (stderr, "junk_write_id3v2: failed to write frame header flags, id %s, size %d\n", f->id, f->size);
3304 goto error;
3305 }
3306 if (write (out, f->data, f->size) != f->size) {
3307 fprintf (stderr, "junk_write_id3v2: failed to write frame data, id %s, size %d\n", f->id, f->size);
3308 goto error;
3309 }
3310 sz += f->size;
3311 }
3312
3313 return 0;
3314
3315 error:
3316 if (buffer) {
3317 free (buffer);
3318 }
3319 return err;
3320 }
3321
3322 int
junk_id3v2_write(FILE * out,DB_id3v2_tag_t * tag)3323 junk_id3v2_write (FILE *out, DB_id3v2_tag_t *tag) {
3324 if (tag->version[0] < 3) {
3325 fprintf (stderr, "junk_write_id3v2: writing id3v2.2 is not supported\n");
3326 return -1;
3327 }
3328
3329 FILE *fp = NULL;
3330 char *buffer = NULL;
3331 int err = -1;
3332
3333 // write tag header
3334 if (fwrite ("ID3", 1, 3, out) != 3) {
3335 fprintf (stderr, "junk_write_id3v2: failed to write ID3 signature\n");
3336 goto error;
3337 }
3338
3339 if (fwrite (tag->version, 1, 2, out) != 2) {
3340 fprintf (stderr, "junk_write_id3v2: failed to write tag version\n");
3341 goto error;
3342 }
3343 uint8_t flags = tag->flags;
3344 flags &= ~(1<<6); // we don't (yet?) write ext header
3345 flags &= ~(1<<4); // we don't write footer
3346
3347 if (fwrite (&flags, 1, 1, out) != 1) {
3348 fprintf (stderr, "junk_write_id3v2: failed to write tag flags\n");
3349 goto error;
3350 }
3351 // run through list of frames, and calculate size
3352 uint32_t sz = 0;
3353 for (DB_id3v2_frame_t *f = tag->frames; f; f = f->next) {
3354 // each tag has 10 bytes header
3355 if (tag->version[0] > 2) {
3356 sz += 10;
3357 }
3358 else {
3359 sz += 6;
3360 }
3361 sz += f->size;
3362 }
3363
3364 trace ("calculated tag size: %d bytes\n", sz);
3365 uint8_t tagsize[4];
3366 tagsize[0] = (sz >> 21) & 0x7f;
3367 tagsize[1] = (sz >> 14) & 0x7f;
3368 tagsize[2] = (sz >> 7) & 0x7f;
3369 tagsize[3] = sz & 0x7f;
3370 if (fwrite (tagsize, 1, 4, out) != 4) {
3371 fprintf (stderr, "junk_write_id3v2: failed to write tag size\n");
3372 goto error;
3373 }
3374
3375 trace ("writing frames\n");
3376 // write frames
3377 for (DB_id3v2_frame_t *f = tag->frames; f; f = f->next) {
3378 trace ("writing frame %s size %d\n", f->id, f->size);
3379 int id_size = 3;
3380 uint8_t frame_size[4];
3381 if (tag->version[0] > 2) {
3382 id_size = 4;
3383 }
3384 if (tag->version[0] == 3) {
3385 frame_size[0] = (f->size >> 24) & 0xff;
3386 frame_size[1] = (f->size >> 16) & 0xff;
3387 frame_size[2] = (f->size >> 8) & 0xff;
3388 frame_size[3] = f->size & 0xff;
3389 }
3390 else if (tag->version[0] == 4) {
3391 frame_size[0] = (f->size >> 21) & 0x7f;
3392 frame_size[1] = (f->size >> 14) & 0x7f;
3393 frame_size[2] = (f->size >> 7) & 0x7f;
3394 frame_size[3] = f->size & 0x7f;
3395 }
3396 if (fwrite (f->id, 1, 4, out) != 4) {
3397 fprintf (stderr, "junk_write_id3v2: failed to write frame id %s\n", f->id);
3398 goto error;
3399 }
3400 if (fwrite (frame_size, 1, 4, out) != 4) {
3401 fprintf (stderr, "junk_write_id3v2: failed to write frame size, id %s, size %d\n", f->id, f->size);
3402 goto error;
3403 }
3404 if (fwrite (f->flags, 1, 2, out) != 2) {
3405 fprintf (stderr, "junk_write_id3v2: failed to write frame header flags, id %s, size %d\n", f->id, f->size);
3406 goto error;
3407 }
3408 if (fwrite (f->data, 1, f->size, out) != f->size) {
3409 fprintf (stderr, "junk_write_id3v2: failed to write frame data, id %s, size %d\n", f->id, f->size);
3410 goto error;
3411 }
3412 sz += f->size;
3413 }
3414
3415 return 0;
3416
3417 error:
3418 if (buffer) {
3419 free (buffer);
3420 }
3421 return err;
3422 }
3423
3424 void
junk_id3v2_free(DB_id3v2_tag_t * tag)3425 junk_id3v2_free (DB_id3v2_tag_t *tag) {
3426 while (tag->frames) {
3427 DB_id3v2_frame_t *next = tag->frames->next;
3428 free (tag->frames);
3429 tag->frames = next;
3430 }
3431 }
3432
3433 void
junk_apev2_free(DB_apev2_tag_t * tag)3434 junk_apev2_free (DB_apev2_tag_t *tag) {
3435 while (tag->frames) {
3436 DB_apev2_frame_t *next = tag->frames->next;
3437 free (tag->frames);
3438 tag->frames = next;
3439 }
3440 }
3441
3442 int
junklib_id3v2_sync_frame(uint8_t * data,int size)3443 junklib_id3v2_sync_frame (uint8_t *data, int size) {
3444 char *writeptr = data;
3445 int skipnext = 0;
3446 int written = 0;
3447 while (size > 0) {
3448 *writeptr = *data;
3449 if (data[0] == 0xff && size >= 2 && data[1] == 0) {
3450 data++;
3451 size--;
3452 }
3453 writeptr++;
3454 data++;
3455 size--;
3456 written++;
3457 }
3458 return written;
3459 }
3460
3461 char *
junk_append_meta(const char * old,const char * new)3462 junk_append_meta (const char *old, const char *new) {
3463 int sz = strlen (old) + strlen (new) + 2;
3464 char *appended = malloc (sz);
3465 if (!appended) {
3466 trace ("junk_append_meta: failed to allocate %d bytes\n");
3467 return NULL;
3468 }
3469 snprintf (appended, sz, "%s\n%s", old, new);
3470 return appended;
3471 }
3472
3473 int
junk_load_comm_frame(int version_major,playItem_t * it,uint8_t * readptr,int synched_size)3474 junk_load_comm_frame (int version_major, playItem_t *it, uint8_t *readptr, int synched_size) {
3475 uint8_t enc = readptr[0];
3476 char lang[4] = {readptr[1], readptr[2], readptr[3], 0};
3477 trace ("COMM enc: %d\n", (int)enc);
3478 trace ("COMM language: %s\n", lang);
3479 trace ("COMM data size: %d\n", synched_size);
3480
3481 char *descr = convstr_id3v2 (version_major, enc, readptr+4, synched_size-4);
3482 if (!descr) {
3483 trace ("failed to decode COMM frame, probably wrong encoding (%d)\n", enc);
3484 return -1;
3485 }
3486
3487 trace ("COMM raw data: %s\n", descr);
3488 // find value
3489 char *value = descr;
3490 while (*value && *value != '\n') {
3491 value++;
3492 }
3493 if (*value != '\n') {
3494 trace ("failed to parse COMM frame, descr was \"%s\"\n", descr);
3495 free (descr);
3496 return -1;
3497 }
3498
3499 *value = 0;
3500 value++;
3501
3502 int len = strlen (descr) + strlen (value) + 3;
3503 char comment[len];
3504
3505 if (*descr) {
3506 snprintf (comment, len, "%s: %s", descr, value);
3507 }
3508 else {
3509 strcpy (comment, value);
3510 }
3511
3512 trace ("COMM combined: %s\n", comment);
3513 // skip utf8 BOM (can be produced by iconv FEFF/FFFE)
3514 int l = strlen (comment);
3515 uint8_t bom[] = { 0xEF, 0xBB, 0xBF };
3516 if (l >= 3 && !memcmp (comment, bom, 3)) {
3517 pl_append_meta (it, "comment", comment+3);
3518 }
3519 else {
3520 pl_append_meta (it, "comment", comment);
3521 }
3522
3523 free (descr);
3524 return 0;
3525 }
3526
3527 /* Parse RVA2 tag */
3528 /* Currently only supports tags wich set master volume and are labeled "track"
3529 * or "album". Also only supports peak value if stored as 16 bits. */
junk_id3v2_load_rva2(int version_major,playItem_t * it,uint8_t * readptr,int synched_size)3530 static int junk_id3v2_load_rva2 (int version_major, playItem_t *it, uint8_t *readptr, int synched_size) {
3531 uint8_t *rva_desc = readptr;
3532 unsigned rva_desc_len = 0;
3533 const uint8_t *p = rva_desc;
3534 while (*p++ && rva_desc_len < synched_size) {
3535 rva_desc_len++;
3536 }
3537
3538 if(rva_desc_len == synched_size) { /* tag too short */
3539 return -1;
3540 }
3541 if(rva_desc_len != 5) { /* only support track or album labeled ones */
3542 return 0;
3543 }
3544
3545 if(synched_size < rva_desc_len + 1 + 4) return -1; /* at least 4 bytes after zero-terminated label */
3546
3547 uint8_t *rva_data = rva_desc + rva_desc_len + 1;
3548
3549 uint8_t vol_type = rva_data[0];
3550
3551 if(vol_type != 1) return 0;
3552
3553 int16_t volume_adjust = (int16_t)(((int16_t)rva_data[1] << 8) | rva_data[2]); /* this is little-endian safe :) */
3554 uint8_t peak_bits = rva_data[3];
3555 uint16_t peak_val = 0;
3556
3557 if(peak_bits == 16 && synched_size >= rva_desc_len + 1 + 6) {
3558 peak_val = (uint16_t)((rva_data[4] << 8) | rva_data[5]);
3559 }
3560
3561 if (!strcasecmp (rva_desc, "album")) {
3562 if (!pl_find_meta (it, ddb_internal_rg_keys[DDB_REPLAYGAIN_ALBUMGAIN])) {
3563 pl_set_item_replaygain (it, DDB_REPLAYGAIN_ALBUMGAIN, (float)volume_adjust / 512.0);
3564 }
3565 if (!pl_find_meta (it, ddb_internal_rg_keys[DDB_REPLAYGAIN_ALBUMPEAK]) && peak_val) {
3566 pl_set_item_replaygain (it, DDB_REPLAYGAIN_ALBUMPEAK, (float)peak_val / 32767.0); /* NOTE: this is a guess based on mp3gain 1.5.2 written tags */
3567 }
3568 }
3569 else if (!strcasecmp (rva_desc, "track")) {
3570 if (!pl_find_meta (it, ddb_internal_rg_keys[DDB_REPLAYGAIN_TRACKGAIN])) {
3571 pl_set_item_replaygain (it, DDB_REPLAYGAIN_TRACKGAIN, (float)volume_adjust / 512.0);
3572 }
3573 if (!pl_find_meta (it, ddb_internal_rg_keys[DDB_REPLAYGAIN_TRACKPEAK]) && peak_val) {
3574 pl_set_item_replaygain (it, DDB_REPLAYGAIN_TRACKPEAK, (float)peak_val / 32767.0);
3575 }
3576 }
3577
3578 return 0;
3579 }
3580
3581 int
junk_id3v2_load_ufid(int version_major,playItem_t * it,uint8_t * readptr,int synched_size)3582 junk_id3v2_load_ufid (int version_major, playItem_t *it, uint8_t *readptr, int synched_size) {
3583 char *owner = readptr;
3584 while (*readptr && synched_size > 0) {
3585 readptr++;
3586 synched_size--;
3587 }
3588 if (!synched_size) {
3589 trace ("UFID owner is not null-terminated\n");
3590 return -1;
3591 }
3592 readptr++;
3593 synched_size--;
3594 char id[synched_size+1];
3595 memcpy (id, readptr, synched_size);
3596 id[synched_size] = 0;
3597
3598 // verify that owner is musicbrainz and that content is ascii
3599 if (strcmp (owner, "http://musicbrainz.org")) {
3600 return -1;
3601 }
3602 for (int i = 0; i < synched_size; i++) {
3603 if (!isascii (id[i])) {
3604 return -1;
3605 }
3606 }
3607
3608 pl_replace_meta (it, "musicbrainz_trackid", id);
3609 return 0;
3610 }
3611
3612 int
junk_id3v2_remove_ufid_frames(DB_id3v2_tag_t * tag,const char * frame_id,const char * owner)3613 junk_id3v2_remove_ufid_frames (DB_id3v2_tag_t *tag, const char *frame_id, const char *owner) {
3614 DB_id3v2_frame_t *prev = NULL;
3615 for (DB_id3v2_frame_t *f = tag->frames; f; ) {
3616 DB_id3v2_frame_t *next = f->next;
3617 if (!strcmp (f->id, frame_id) && f->size >= strlen(owner) && !strcmp (f->data, owner)) {
3618 if (prev) {
3619 prev->next = f->next;
3620 }
3621 else {
3622 tag->frames = f->next;
3623 }
3624 free (f);
3625 }
3626 else {
3627 prev = f;
3628 }
3629 f = next;
3630 }
3631 return 0;
3632 }
3633
3634 DB_id3v2_frame_t *
junk_id3v2_add_ufid_frame(DB_id3v2_tag_t * tag,const char * owner,const char * id,int id_len)3635 junk_id3v2_add_ufid_frame (DB_id3v2_tag_t *tag, const char *owner, const char *id, int id_len) {
3636 int ownerlen = strlen (owner);
3637 int len = ownerlen + 1 + id_len;
3638
3639 // make a frame
3640 trace ("calculated frame size = %d\n", len);
3641 DB_id3v2_frame_t *f = malloc (len + sizeof (DB_id3v2_frame_t));
3642 memset (f, 0, sizeof (DB_id3v2_frame_t));
3643 strcpy (f->id, "UFID");
3644 f->size = len;
3645 memcpy (f->data, owner, ownerlen+1);
3646 memcpy (f->data+ownerlen+1, id, id_len);
3647 // append to tag
3648 DB_id3v2_frame_t *tail;
3649 for (tail = tag->frames; tail && tail->next; tail = tail->next);
3650 if (tail) {
3651 tail->next = f;
3652 }
3653 else {
3654 tag->frames = f;
3655 }
3656
3657 return f;
3658 }
3659
3660 int
junk_id3v2_load_txx(int version_major,playItem_t * it,uint8_t * readptr,int synched_size)3661 junk_id3v2_load_txx (int version_major, playItem_t *it, uint8_t *readptr, int synched_size) {
3662 char *txx = convstr_id3v2 (version_major, *readptr, readptr+1, synched_size-1);
3663 if (!txx) {
3664 return -1;
3665 }
3666
3667 char *val = NULL;
3668 if (txx) {
3669 char *p;
3670 for (p = txx; *p; p++) {
3671 if (*p == '\n') {
3672 *p = 0;
3673 val = p+1;
3674 break;
3675 }
3676 }
3677 }
3678
3679 if (val) {
3680 // skip utf8 BOM (can be produced by iconv FEFF/FFFE)
3681 int l = strlen (val);
3682 uint8_t bom[] = { 0xEF, 0xBB, 0xBF };
3683 if (l >= 3 && !memcmp (val, bom, 3)) {
3684 val += 3;
3685 }
3686
3687 if (!strcasecmp (txx, "replaygain_album_gain")) {
3688 pl_set_item_replaygain (it, DDB_REPLAYGAIN_ALBUMGAIN, atof (val));
3689 }
3690 else if (!strcasecmp (txx, "replaygain_album_peak")) {
3691 pl_set_item_replaygain (it, DDB_REPLAYGAIN_ALBUMPEAK, atof (val));
3692 }
3693 else if (!strcasecmp (txx, "replaygain_track_gain")) {
3694 pl_set_item_replaygain (it, DDB_REPLAYGAIN_TRACKGAIN, atof (val));
3695 }
3696 else if (!strcasecmp (txx, "replaygain_track_peak")) {
3697 pl_set_item_replaygain (it, DDB_REPLAYGAIN_TRACKPEAK, atof (val));
3698 }
3699 else if (!strcasecmp (txx, "date")) { // HACK: fb2k date support
3700 pl_append_meta (it, "year", val);
3701 }
3702 else {
3703 pl_append_meta (it, txx, val);
3704 }
3705 }
3706
3707 free (txx);
3708
3709 return 0;
3710 }
3711
3712 int
junk_id3v2_add_genre(playItem_t * it,char * genre)3713 junk_id3v2_add_genre (playItem_t *it, char *genre) {
3714 int numeric = 0;
3715 if (genre[0] == '(') {
3716 // find matching parenthesis
3717 char *p = &genre[1];
3718 while (*p && *p != ')') {
3719 if (!isdigit (*p)) {
3720 break;
3721 }
3722 p++;
3723 }
3724 if (*p == ')') {
3725 *p = 0;
3726 memmove (genre, genre+1, p-genre);
3727 numeric = 1;
3728 }
3729 }
3730 if (!numeric) {
3731 // check if it is numeric
3732 const char *p = genre;
3733 while (*p) {
3734 if (!isdigit (*p)) {
3735 break;
3736 }
3737 p++;
3738 }
3739 if (*p == 0 && p > genre) {
3740 numeric = 1;
3741 }
3742 }
3743
3744 if (numeric) {
3745 int genre_id = atoi (genre);
3746 if (genre_id >= 0) {
3747 const char *genre_str = NULL;
3748 if (genre_id < ID3V1_GENRE_COUNT) {
3749 genre_str = junk_genretbl[genre_id];
3750 }
3751 else if (genre_id == 0xff) {
3752 // genre_str = "None";
3753 }
3754 if (genre_str) {
3755 pl_add_meta (it, "genre", genre_str);
3756 return 0;
3757 }
3758 }
3759 }
3760 else if (!strcmp (genre, "CR")) {
3761 pl_add_meta (it, "genre", "Cover");
3762 }
3763 else if (!strcmp (genre, "RX")) {
3764 pl_add_meta (it, "genre", "Remix");
3765 }
3766 else {
3767 pl_add_meta (it, "genre", genre);
3768 }
3769
3770 return 0;
3771 }
3772
3773 int
junk_id3v2_read_full(playItem_t * it,DB_id3v2_tag_t * tag_store,DB_FILE * fp)3774 junk_id3v2_read_full (playItem_t *it, DB_id3v2_tag_t *tag_store, DB_FILE *fp) {
3775 DB_id3v2_frame_t *tail = NULL;
3776 int title_added = 0;
3777 if (!fp) {
3778 trace ("bad call to junk_id3v2_read!\n");
3779 return -1;
3780 }
3781 deadbeef->rewind (fp);
3782 uint8_t header[10];
3783 if (deadbeef->fread (header, 1, 10, fp) != 10) {
3784 return -1; // too short
3785 }
3786 if (strncmp (header, "ID3", 3)) {
3787 return -1; // no tag
3788 }
3789 uint8_t version_major = header[3];
3790 uint8_t version_minor = header[4];
3791 if (version_major > 4 || version_major < 2) {
3792 trace ("id3v2.%d.%d is unsupported\n", version_major, version_minor);
3793 return -1; // unsupported
3794 }
3795 uint8_t flags = header[5];
3796 if (flags & 15) {
3797 trace ("unrecognized flags: one of low 15 bits is set, value=0x%x\n", (int)flags);
3798 return -1; // unsupported
3799 }
3800 int unsync = (flags & (1<<7)) ? 1 : 0;
3801 int extheader = (flags & (1<<6)) ? 1 : 0;
3802 int expindicator = (flags & (1<<5)) ? 1 : 0;
3803 int footerpresent = (flags & (1<<4)) ? 1 : 0;
3804 // check for bad size
3805 if ((header[9] & 0x80) || (header[8] & 0x80) || (header[7] & 0x80) || (header[6] & 0x80)) {
3806 trace ("bad header size\n");
3807 return -1; // bad header
3808 }
3809 uint32_t size = (header[9] << 0) | (header[8] << 7) | (header[7] << 14) | (header[6] << 21);
3810
3811 trace ("tag size: %d\n", size);
3812 if (size == 0) {
3813 return -1;
3814 }
3815 if (tag_store) {
3816 tag_store->version[0] = version_major;
3817 tag_store->version[1] = version_minor;
3818 tag_store->flags = flags;
3819 // remove unsync flag
3820 tag_store->flags &= ~ (1<<7);
3821 }
3822
3823 uint8_t *tag = malloc (size);
3824 if (!tag) {
3825 fprintf (stderr, "junklib: out of memory while reading id3v2, tried to alloc %d bytes\n", size);
3826 goto error;
3827 }
3828 if (deadbeef->fread (tag, 1, size, fp) != size) {
3829 goto error; // bad size
3830 }
3831 uint8_t *readptr = tag;
3832 int crcpresent = 0;
3833 trace ("version: 2.%d.%d, unsync: %d, extheader: %d, experimental: %d\n", version_major, version_minor, unsync, extheader, expindicator);
3834
3835 if (extheader) {
3836 uint32_t sz = (readptr[3] << 0) | (readptr[2] << 7) | (readptr[1] << 14) | (readptr[0] << 21);
3837 if (size < sz) {
3838 trace ("error: size of ext header (%d) is greater than tag size\n", sz);
3839 goto error; // bad size
3840 }
3841 readptr += sz;
3842 }
3843 int err = -1;
3844 while (readptr - tag <= size - 4 && *readptr) {
3845 if (version_major == 3 || version_major == 4) {
3846 trace ("pos %d of %d\n", readptr - tag, size);
3847 char frameid[5];
3848 memcpy (frameid, readptr, 4);
3849 frameid[4] = 0;
3850 readptr += 4;
3851 if (readptr - tag >= size - 4) {
3852 trace ("reached the end of tag\n");
3853 break;
3854 }
3855 uint32_t sz;
3856 if (version_major == 4) {
3857 sz = (readptr[3] << 0) | (readptr[2] << 7) | (readptr[1] << 14) | (readptr[0] << 21);
3858 }
3859 else if (version_major == 3) {
3860 sz = (readptr[3] << 0) | (readptr[2] << 8) | (readptr[1] << 16) | (readptr[0] << 24);
3861 }
3862 else {
3863 trace ("unknown id3v2 version (2.%d.%d)\n", version_major, version_minor);
3864 goto error;
3865 }
3866 readptr += 4;
3867 trace ("got frame %s, size %d, pos %d, tagsize %d\n", frameid, sz, readptr-tag, size);
3868 if (readptr - tag >= size - sz) {
3869 trace ("frame is out of tag bounds\n");
3870 err = -1;
3871 goto error; // size of frame is more than size of tag
3872 }
3873 if (sz < 1) {
3874 // err = 1;
3875 break; // frame must be at least 1 byte long
3876 }
3877 uint8_t flags1 = readptr[0];
3878 uint8_t flags2 = readptr[1];
3879 readptr += 2;
3880
3881 if (!strcmp (frameid, "APIC")) {
3882 if (sz > MAX_ID3V2_APIC_FRAME_SIZE) {
3883 trace ("junk_id3v2_read_full: frame %s size is too big (%d), discarded\n", frameid, sz);
3884 readptr += sz;
3885 continue;
3886 }
3887 }
3888 else if (sz > MAX_ID3V2_FRAME_SIZE || readptr - tag + sz > size) {
3889 trace ("junk_id3v2_read_full: frame %s size is too big (%d), discarded\n", frameid, sz);
3890 readptr += sz;
3891 continue;
3892 }
3893 int synched_size = sz;
3894 if (unsync) {
3895 synched_size = junklib_id3v2_sync_frame (readptr, sz);
3896 trace ("size: %d/%d\n", synched_size, sz);
3897 }
3898
3899 if (tag_store) {
3900 DB_id3v2_frame_t *frm = malloc (sizeof (DB_id3v2_frame_t) + sz);
3901 if (!frm) {
3902 fprintf (stderr, "junklib: failed to alloc %d bytes for id3v2 frame %s\n", (int)(sizeof (DB_id3v2_frame_t) + sz), frameid);
3903 goto error;
3904 }
3905 memset (frm, 0, sizeof (DB_id3v2_frame_t));
3906 if (tail) {
3907 tail->next = frm;
3908 }
3909 tail = frm;
3910 if (!tag_store->frames) {
3911 tag_store->frames = frm;
3912 }
3913 strcpy (frm->id, frameid);
3914 memcpy (frm->data, readptr, sz);
3915 frm->size = synched_size;
3916
3917 frm->flags[0] = flags1;
3918 frm->flags[1] = flags2;
3919 }
3920 if (version_major == 4) {
3921 if (flags1 & 0x8f) {
3922 // unknown flags
3923 trace ("unknown status flags: %02x\n", flags1);
3924 readptr += sz;
3925 continue;
3926 }
3927 if (flags2 & 0xb0) {
3928 // unknown flags
3929 trace ("unknown format flags: %02x\n", flags2);
3930 readptr += sz;
3931 continue;
3932 }
3933
3934 if (flags2 & 0x40) { // group id
3935 trace ("frame has group id\n");
3936 readptr++; // skip id
3937 sz--;
3938 }
3939 if (flags2 & 0x08) { // compressed frame, ignore
3940 trace ("frame is compressed, skipping\n");
3941 readptr += sz;
3942 continue;
3943 }
3944 if (flags2 & 0x04) { // encrypted frame, skip
3945 trace ("frame is encrypted, skipping\n");
3946 readptr += sz;
3947 continue;
3948 }
3949 if (flags2 & 0x02) { // unsync, just do nothing
3950 }
3951 if (flags2 & 0x01) { // data size
3952 synched_size = (readptr[3] << 0) | (readptr[2] << 7) | (readptr[1] << 14) | (readptr[0] << 21);
3953 trace ("frame has extra size field = %d\n", synched_size);
3954 readptr += 4;
3955 sz -= 4;
3956 }
3957 }
3958 else if (version_major == 3) {
3959 if (flags1 & 0x1F) {
3960 trace ("unknown status flags: %02x\n", flags1);
3961 readptr += sz;
3962 continue;
3963 }
3964 if (flags2 & 0x1F) {
3965 trace ("unknown format flags: %02x\n", flags2);
3966 readptr += sz;
3967 continue;
3968 }
3969 if (flags2 & 0x80) {
3970 trace ("frame is compressed, skipping\n");
3971 readptr += sz;
3972 continue;
3973 }
3974 if (flags2 & 0x40) {
3975 trace ("frame is encrypted, skipping\n");
3976 readptr += sz;
3977 continue;
3978 }
3979 if (flags2 & 0x20) {
3980 trace ("frame has group id\n");
3981 readptr++; // skip id
3982 sz--;
3983 }
3984 }
3985
3986 // parse basic 2.3/2.4 text frames
3987 //const char *text_frames[] = { "TPE1", "TPE2", "TPOS", "TIT2", "TALB", "TCOP", "TCON", "TENC", "TPE3", "TCOM", "TRCK", "TYER", "TDRC", NULL };
3988 //char **text_holders[] = { &artist, &band, &disc, &title, &album, ©right, &genre, &vendor, &performer, &composer, &track, version_major == 3 ? &year : NULL, version_major == 4 ? &year : NULL, };
3989 if (it) {
3990 int added = 0;
3991 if (strcmp (frameid, "TXXX")) {
3992 for (int f = 0; frame_mapping[f]; f += FRAME_MAPPINGS) {
3993 const char *frm_name = version_major == 3 ? frame_mapping[f+MAP_ID3V23] : frame_mapping[f+MAP_ID3V24];
3994 if (frm_name && !strcmp (frameid, frm_name)) {
3995 added = 1;
3996 if (synched_size > MAX_TEXT_FRAME_SIZE) {
3997 trace ("frame %s is too big, discard\n", frameid);
3998 break;
3999 }
4000
4001 char *text = convstr_id3v2 (version_major, readptr[0], readptr+1, synched_size-1);
4002
4003 // couple of simple tests
4004 //char *text = convstr_id3v2 (4, 3, "текст1\0текст2", strlen ("текст1")*2+2);
4005 //const char ucstext[] = { 0x42, 0x04, 0x35, 0x04, 0x3a, 0x04, 0x41, 0x04, 0x42, 0x04, 0x31, 0x00, 0x00, 0x00, 0x42, 0x04, 0x35, 0x04, 0x3a, 0x04, 0x41, 0x04, 0x42, 0x04, 0x32, 0x00 };
4006 //char *text = convstr_id3v2 (4, 1, ucstext, sizeof (ucstext));
4007
4008 if (text && *text) {
4009 if (!strcmp (frameid, "TRCK")) { // special case for track/totaltracks
4010 junk_add_track_meta (it, text);
4011 }
4012 if (!strcmp (frameid, "TPOS")) { // special case for disc/totaldiscs
4013 junk_add_disc_meta (it, text);
4014 }
4015 else if (!strcmp (frameid, "TCON")) {
4016 junk_id3v2_add_genre (it, text);
4017 }
4018 else {
4019 pl_append_meta (it, frame_mapping[f+MAP_DDB], text);
4020 }
4021 // if (text) {
4022 // trace ("%s = %s\n", frameid, text);
4023 // }
4024 }
4025 if (text) {
4026 free (text);
4027 }
4028 break;
4029 }
4030 }
4031 }
4032
4033 if (added) {
4034 readptr += sz;
4035 continue;
4036 }
4037
4038 if (!strcmp (frameid, "COMM")) {
4039 if (sz < 4) {
4040 trace ("COMM frame is too short, skipped\n");
4041 readptr += sz; // bad tag
4042 continue;
4043 }
4044
4045 /*int res = */junk_load_comm_frame (version_major, it, readptr, synched_size);
4046 }
4047 else if (it && !strcmp (frameid, "RVA2")) {
4048 if (synched_size < 5) {
4049 trace ("RVA2 frame is too short, skipped\n");
4050 readptr += sz; // bad tag
4051 continue;
4052 }
4053
4054 /*int res = */junk_id3v2_load_rva2(version_major, it, readptr, synched_size);
4055 }
4056 else if (it && !strcmp (frameid, "UFID")) {
4057 if (synched_size < 2) {
4058 trace ("UFID frame is too short, skipped\n");
4059 readptr += sz; // bad tag
4060 continue;
4061 }
4062 junk_id3v2_load_ufid (version_major, it, readptr, synched_size);
4063 }
4064 else if (it && !strcmp (frameid, "TXXX")) {
4065 if (synched_size < 2) {
4066 trace ("TXXX frame is too short, skipped\n");
4067 readptr += sz; // bad tag
4068 continue;
4069 }
4070 int res = junk_id3v2_load_txx (version_major, it, readptr, synched_size);
4071 }
4072 }
4073 readptr += sz;
4074 }
4075 else if (version_major == 2) {
4076 char frameid[4];
4077 memcpy (frameid, readptr, 3);
4078 frameid[3] = 0;
4079 readptr += 3;
4080 if (readptr - tag >= size - 3) {
4081 break;
4082 }
4083 uint32_t sz = (readptr[2] << 0) | (readptr[1] << 8) | (readptr[0] << 16);
4084 readptr += 3;
4085 if (readptr - tag >= size - sz) {
4086 break; // size of frame is less than size of tag
4087 }
4088 if (sz < 1) {
4089 break; // frame must be at least 1 byte long
4090 }
4091 if (sz > MAX_ID3V2_FRAME_SIZE) {
4092 trace ("junk_id3v2_read_full: frame %s size is too big, discarded\n", frameid);
4093 readptr += sz;
4094 continue;
4095 }
4096 int synched_size = sz;
4097 if (unsync) {
4098 synched_size = junklib_id3v2_sync_frame (readptr, sz);
4099 }
4100
4101 if (tag_store) {
4102 DB_id3v2_frame_t *frm = malloc (sizeof (DB_id3v2_frame_t) + sz);
4103 if (!frm) {
4104 fprintf (stderr, "junklib: failed to alloc %d bytes for id3v2.2 frame %s\n", (int)(sizeof (DB_id3v2_frame_t) + sz), frameid);
4105 goto error;
4106 }
4107 memset (frm, 0, sizeof (DB_id3v2_frame_t));
4108 if (tail) {
4109 tail->next = frm;
4110 }
4111 tail = frm;
4112 if (!tag_store->frames) {
4113 tag_store->frames = frm;
4114 }
4115 strcpy (frm->id, frameid);
4116 memcpy (frm->data, readptr, synched_size);
4117 frm->size = sz;
4118 }
4119 // trace ("found id3v2.2 frame: %s, size=%d\n", frameid, sz);
4120
4121 // parse basic 2.2 text frames
4122 if (it) {
4123 int added = 0;
4124 if (strcmp (frameid, "TXX")) {
4125 for (int f = 0; frame_mapping[f]; f++) {
4126 if (frame_mapping[f+MAP_ID3V22] && !strcmp (frameid, frame_mapping[f+MAP_ID3V22])) {
4127 added = 1;
4128 if (synched_size > MAX_TEXT_FRAME_SIZE) {
4129 trace ("frame %s is too big, discard\n", frameid);
4130 break;
4131 }
4132 char *text = convstr_id3v2 (version_major, readptr[0], readptr+1, synched_size-1);
4133 if (text && *text) {
4134 if (!strcmp (frameid, "TRK")) { // special case for track/totaltracks
4135 junk_add_track_meta (it, text);
4136 }
4137 if (!strcmp (frameid, "TPA")) { // special case for disc/totaldiscs
4138 junk_add_disc_meta (it, text);
4139 }
4140 else if (!strcmp (frameid, "TCO")) {
4141 junk_id3v2_add_genre (it, text);
4142 }
4143 else {
4144 pl_append_meta (it, frame_mapping[f+MAP_DDB], text);
4145 }
4146 free (text);
4147 }
4148 break;
4149 }
4150 }
4151 }
4152
4153 if (added) {
4154 readptr += sz;
4155 continue;
4156 }
4157
4158 if (!strcmp (frameid, "COM")) {
4159 if (synched_size < 6) {
4160 readptr += sz;
4161 continue;
4162 }
4163 /*int res = */junk_load_comm_frame (version_major, it, readptr, synched_size);
4164 }
4165 else if (it && !strcmp (frameid, "TXX")) {
4166 if (synched_size < 2) {
4167 trace ("TXX frame is too short, skipped\n");
4168 readptr += sz; // bad tag
4169 continue;
4170 }
4171 int res = junk_id3v2_load_txx (version_major, it, readptr, synched_size);
4172 }
4173 }
4174 readptr += sz;
4175 }
4176 else {
4177 trace ("id3v2.%d (unsupported!)\n", version_minor);
4178 }
4179 }
4180 if (it) {
4181 if (version_major == 2) {
4182 uint32_t f = pl_get_item_flags (it);
4183 f |= DDB_TAG_ID3V22;
4184 pl_set_item_flags (it, f);
4185 }
4186 else if (version_major == 3) {
4187 uint32_t f = pl_get_item_flags (it);
4188 f |= DDB_TAG_ID3V23;
4189 pl_set_item_flags (it, f);
4190 }
4191 else if (version_major == 4) {
4192 uint32_t f = pl_get_item_flags (it);
4193 f |= DDB_TAG_ID3V24;
4194 pl_set_item_flags (it, f);
4195 }
4196 }
4197 err = 0;
4198 error:
4199 if (err != 0) {
4200 trace ("error parsing id3v2\n");
4201 }
4202
4203 if (tag) {
4204 free (tag);
4205 }
4206 if (tag_store && err != 0) {
4207 while (tag_store->frames) {
4208 DB_id3v2_frame_t *next = tag_store->frames->next;
4209 free (tag_store->frames);
4210 tag_store->frames = next;
4211 }
4212 }
4213 return err;
4214 }
4215
4216 int
junk_id3v2_read(playItem_t * it,DB_FILE * fp)4217 junk_id3v2_read (playItem_t *it, DB_FILE *fp) {
4218 return junk_id3v2_read_full (it, NULL, fp);
4219 }
4220
4221 const char *
junk_detect_charset_len(const char * s,int len)4222 junk_detect_charset_len (const char *s, int len) {
4223 // check if that's already utf8
4224 if (u8_valid (s, len, NULL)) {
4225 return NULL; // means no recoding required
4226 }
4227 // try shift-jis
4228 if (enable_shift_jis_detection && can_be_shift_jis (s, len)) {
4229 return "shift-jis";
4230 }
4231 // hack to add cp936 support
4232 if (can_be_chinese (s, len)) {
4233 return "cp936";
4234 }
4235 // check if that could be non-latin1 (too many nonascii chars)
4236 if (can_be_russian (s, len)) {
4237 return "cp1251";
4238 }
4239
4240 return "cp1252";
4241 }
4242
4243 const char *
junk_detect_charset(const char * s)4244 junk_detect_charset (const char *s) {
4245 size_t len = strlen (s);
4246 return junk_detect_charset_len (s, len);
4247 }
4248
4249 int
junk_recode(const char * in,int inlen,char * out,int outlen,const char * cs)4250 junk_recode (const char *in, int inlen, char *out, int outlen, const char *cs) {
4251 return junk_iconv (in, inlen, out, outlen, cs, UTF8_STR);
4252 }
4253
4254 int
junk_rewrite_tags(playItem_t * it,uint32_t junk_flags,int id3v2_version,const char * id3v1_encoding)4255 junk_rewrite_tags (playItem_t *it, uint32_t junk_flags, int id3v2_version, const char *id3v1_encoding) {
4256 trace ("junk_rewrite_tags %X\n", junk_flags);
4257 int err = -1;
4258 char *buffer = NULL;
4259 DB_FILE *fp = NULL;
4260 int out = -1;
4261
4262 uint32_t item_flags = pl_get_item_flags (it);
4263
4264 // get options
4265 int strip_id3v2 = junk_flags & JUNK_STRIP_ID3V2;
4266 int strip_id3v1 = junk_flags & JUNK_STRIP_ID3V1;
4267 int strip_apev2 = junk_flags & JUNK_STRIP_APEV2;
4268 int write_id3v2 = junk_flags & JUNK_WRITE_ID3V2;
4269 int write_id3v1 = junk_flags & JUNK_WRITE_ID3V1;
4270 int write_apev2 = junk_flags & JUNK_WRITE_APEV2;
4271
4272 char tmppath[PATH_MAX];
4273 // find the beginning and the end of audio data
4274 char fname[PATH_MAX];
4275 pl_get_meta (it, ":URI", fname, sizeof (fname));
4276 snprintf (tmppath, sizeof (tmppath), "%s.temp", fname);
4277 fp = deadbeef->fopen (fname);
4278 if (!fp) {
4279 trace ("file not found %s\n", fname);
4280 return -1;
4281 }
4282
4283 int64_t fsize = deadbeef->fgetlength (fp);
4284 int id3v2_size = 0;
4285 int id3v2_start = deadbeef->junk_id3v2_find (fp, &id3v2_size);
4286 if (id3v2_start == -1) {
4287 id3v2_size = -1;
4288 }
4289
4290 int32_t apev2_size;
4291 uint32_t flags, numitems;
4292 int64_t apev2_start = junk_apev2_find2 (fp, &apev2_size, &flags, &numitems);
4293 if (apev2_start == -1) {
4294 apev2_start = 0;
4295 }
4296
4297 if (!strip_apev2 && !write_apev2) {
4298 apev2_start = 0;
4299 }
4300
4301 int64_t id3v1_start = junk_id3v1_find2 (fp);
4302 if (id3v1_start == -1) {
4303 id3v1_start = 0;
4304 }
4305
4306 int64_t header = 0;
4307 if (id3v2_size > 0) {
4308 header = id3v2_start + id3v2_size;
4309 }
4310
4311 int64_t footer = fsize;
4312
4313 if (id3v1_start > 0) {
4314 footer = id3v1_start;
4315 }
4316 if (apev2_start > 0) {
4317 footer = min (footer, apev2_start);
4318 }
4319
4320 trace ("header size: %lld, footer size: %lld\n", header, fsize-footer);
4321
4322 // "TRCK" -- special case
4323 // "TYER"/"TDRC" -- special case
4324
4325 // open output file
4326 struct stat stat_struct;
4327 if (stat(fname, &stat_struct) != 0) {
4328 stat_struct.st_mode = 00640;
4329 }
4330 out = open (tmppath, O_CREAT | O_LARGEFILE | O_WRONLY, stat_struct.st_mode);
4331 trace ("will write tags into %s\n", tmppath);
4332 if (out < 0) {
4333 fprintf (stderr, "cmp3_write_metadata: failed to open temp file %s\n", tmppath);
4334 goto error;
4335 }
4336
4337 DB_id3v2_tag_t id3v2;
4338 DB_apev2_tag_t apev2;
4339
4340 memset (&id3v2, 0, sizeof (id3v2));
4341 memset (&apev2, 0, sizeof (apev2));
4342
4343 if (!strip_id3v2 && !write_id3v2 && id3v2_size > 0) {
4344 if (deadbeef->fseek (fp, id3v2_start, SEEK_SET) == -1) {
4345 trace ("cmp3_write_metadata: failed to seek to original id3v2 tag position in %s\n", pl_find_meta (it, ":URI"));
4346 goto error;
4347 }
4348 uint8_t *buf = malloc (id3v2_size);
4349 if (!buf) {
4350 trace ("cmp3_write_metadata: failed to alloc %d bytes for id3v2 tag\n", id3v2_size);
4351 goto error;
4352 }
4353 if (deadbeef->fread (buf, 1, id3v2_size, fp) != id3v2_size) {
4354 trace ("cmp3_write_metadata: failed to read original id3v2 tag from %s\n", pl_find_meta (it, ":URI"));
4355 free (buf);
4356 goto error;
4357 }
4358 if (write (out, buf, id3v2_size) != id3v2_size) {
4359 trace ("cmp3_write_metadata: failed to copy original id3v2 tag from %s to temp file\n", pl_find_meta (it, ":URI"));
4360 free (buf);
4361 goto error;
4362 }
4363 free (buf);
4364 }
4365 else if (write_id3v2) {
4366 trace ("writing id3v2\n");
4367 if (id3v2_size <= 0 || strip_id3v2 || deadbeef->junk_id3v2_read_full (NULL, &id3v2, fp) != 0) {
4368 deadbeef->junk_id3v2_free (&id3v2);
4369 memset (&id3v2, 0, sizeof (id3v2));
4370 id3v2.version[0] = id3v2_version;
4371 }
4372 // convert to required version
4373 while (id3v2.version[0] != id3v2_version) {
4374 DB_id3v2_tag_t converted;
4375 memset (&converted, 0, sizeof (converted));
4376 if (id3v2.version[0] == 2) {
4377 if (deadbeef->junk_id3v2_convert_22_to_24 (&id3v2, &converted) != 0) {
4378 goto error;
4379 }
4380 deadbeef->junk_id3v2_free (&id3v2);
4381 memcpy (&id3v2, &converted, sizeof (DB_id3v2_tag_t));
4382 continue;
4383 }
4384 else if (id3v2.version[0] == 3) {
4385 if (deadbeef->junk_id3v2_convert_23_to_24 (&id3v2, &converted) != 0) {
4386 goto error;
4387 }
4388 deadbeef->junk_id3v2_free (&id3v2);
4389 memcpy (&id3v2, &converted, sizeof (DB_id3v2_tag_t));
4390 continue;
4391 }
4392 else if (id3v2.version[0] == 4) {
4393 if (deadbeef->junk_id3v2_convert_24_to_23 (&id3v2, &converted) != 0) {
4394 goto error;
4395 }
4396 deadbeef->junk_id3v2_free (&id3v2);
4397 memcpy (&id3v2, &converted, sizeof (DB_id3v2_tag_t));
4398 continue;
4399 }
4400 }
4401
4402 junk_id3v2_remove_all_txxx_frames (&id3v2);
4403
4404 pl_lock ();
4405 {
4406 // COMM
4407 junk_id3v2_remove_frames (&id3v2, "COMM");
4408 const char *val = pl_find_meta (it, "comment");
4409 if (val && *val) {
4410 junk_id3v2_add_comment_frame (&id3v2, "eng", "", val);
4411 }
4412 // UFID
4413 junk_id3v2_remove_ufid_frames (&id3v2, "UFID", "http://musicbrainz.org");
4414 val = pl_find_meta (it, "musicbrainz_trackid");
4415 if (val && *val) {
4416 junk_id3v2_add_ufid_frame (&id3v2, "http://musicbrainz.org", val, strlen (val));
4417 }
4418 }
4419 pl_unlock ();
4420
4421 // remove all known normal frames (they will be refilled from track metadata)
4422 int idx = id3v2.version[0] == 3 ? MAP_ID3V23 : MAP_ID3V24;
4423 for (int i = 0; frame_mapping[i]; i += FRAME_MAPPINGS) {
4424 if (frame_mapping[i+idx]) {
4425 junk_id3v2_remove_frames (&id3v2, frame_mapping[i+idx]);
4426 trace ("removed frame %s\n", frame_mapping[i+idx]);
4427 }
4428 }
4429
4430 DB_metaInfo_t *meta = pl_get_metadata_head (it);
4431 while (meta) {
4432 if (meta->value && *meta->value) {
4433 int i;
4434 for (i = 0; frame_mapping[i]; i += FRAME_MAPPINGS) {
4435 if (!strcasecmp (meta->key, frame_mapping[i+MAP_DDB])) {
4436 const char *frm_name = id3v2_version == 3 ? frame_mapping[i+MAP_ID3V23] : frame_mapping[i+MAP_ID3V24];
4437 if (frm_name) {
4438 // field is known and supported for this tag version
4439 trace ("add_frame %s %s\n", frm_name, meta->value);
4440 junk_id3v2_add_text_frame (&id3v2, frm_name, meta->value);
4441 }
4442 break;
4443 }
4444 }
4445 if (!frame_mapping[i]
4446 && meta->key[0] != ':'
4447 && strcasecmp (meta->key, "comment")
4448 && strcasecmp (meta->key, "track")
4449 && strcasecmp (meta->key, "numtracks")
4450 && strcasecmp (meta->key, "disc")
4451 && strcasecmp (meta->key, "numdiscs")
4452 ) {
4453 // add as txxx
4454 trace ("adding unknown frame as TXX %s=%s\n", meta->key, meta->value);
4455 junk_id3v2_remove_txxx_frame (&id3v2, meta->key);
4456 junk_id3v2_add_txxx_frame (&id3v2, meta->key, meta->value);
4457 }
4458 }
4459 meta = meta->next;
4460 }
4461
4462 pl_lock ();
4463 {
4464 // add tracknumber/totaltracks
4465 const char *track = pl_find_meta (it, "track");
4466 const char *totaltracks = pl_find_meta (it, "numtracks");
4467 if (track && totaltracks) {
4468 char s[100];
4469 snprintf (s, sizeof (s), "%s/%s", track, totaltracks);
4470 junk_id3v2_remove_frames (&id3v2, "TRCK");
4471 junk_id3v2_add_text_frame (&id3v2, "TRCK", s);
4472 }
4473 else if (track) {
4474 junk_id3v2_remove_frames (&id3v2, "TRCK");
4475 junk_id3v2_add_text_frame (&id3v2, "TRCK", track);
4476 }
4477 // add discnumber/totaldiscs
4478 const char *disc = pl_find_meta (it, "disc");
4479 const char *totaldiscs = pl_find_meta (it, "numdiscs");
4480 if (disc && totaldiscs) {
4481 char s[100];
4482 snprintf (s, sizeof (s), "%s/%s", disc, totaldiscs);
4483 junk_id3v2_remove_frames (&id3v2, "TPOS");
4484 junk_id3v2_add_text_frame (&id3v2, "TPOS", s);
4485 }
4486 else if (disc) {
4487 junk_id3v2_remove_frames (&id3v2, "TPOS");
4488 junk_id3v2_add_text_frame (&id3v2, "TPOS", disc);
4489 }
4490 }
4491 pl_unlock ();
4492
4493 // remove and re-add replaygain id3v2 frames
4494 for (int n = 0; ddb_internal_rg_keys[n]; n++) {
4495 junk_id3v2_remove_txxx_frame (&id3v2, tag_rg_names[n]);
4496 if (pl_find_meta (it, ddb_internal_rg_keys[n])) {
4497 float value = pl_get_item_replaygain (it, n);
4498 char s[100];
4499 snprintf (s, sizeof (s), "%f", value);
4500 junk_id3v2_add_txxx_frame (&id3v2, tag_rg_names[n], s);
4501 }
4502 }
4503
4504 // write tag
4505 if (junk_id3v2_write2 (out, &id3v2) != 0) {
4506 trace ("cmp3_write_metadata: failed to write id3v2 tag to %s\n", pl_find_meta (it, ":URI"))
4507 goto error;
4508 }
4509 }
4510
4511 // now write audio data
4512 buffer = malloc (8192);
4513 deadbeef->fseek (fp, header, SEEK_SET);
4514 int64_t writesize = fsize;
4515 if (footer > 0) {
4516 writesize -= (fsize - footer);
4517 }
4518 writesize -= header;
4519 trace ("writesize: %d, id3v1_start: %d(%d), apev2_start: %d, footer: %d\n", writesize, id3v1_start, fsize-id3v1_start, apev2_start, footer);
4520
4521 while (writesize > 0) {
4522 int rb = min (8192, writesize);
4523 rb = deadbeef->fread (buffer, 1, rb, fp);
4524 if (rb < 0) {
4525 fprintf (stderr, "junk_write_id3v2: error reading input data\n");
4526 goto error;
4527 }
4528 if (write (out, buffer, rb) != rb) {
4529 fprintf (stderr, "junk_write_id3v2: error writing output file\n");
4530 goto error;
4531 }
4532 if (rb == 0) {
4533 break; // eof
4534 }
4535 writesize -= rb;
4536 }
4537
4538 if (!write_apev2 && !strip_apev2 && apev2_start != 0) {
4539 trace ("copying original apev2 tag\n");
4540 if (deadbeef->fseek (fp, apev2_start, SEEK_SET) == -1) {
4541 trace ("cmp3_write_metadata: failed to seek to original apev2 tag position in %s\n", pl_find_meta (it, ":URI"));
4542 goto error;
4543 }
4544 uint8_t *buf = malloc (apev2_size);
4545 if (!buf) {
4546 trace ("cmp3_write_metadata: failed to alloc %d bytes for apev2 tag\n", apev2_size);
4547 goto error;
4548 }
4549 if (deadbeef->fread (buf, 1, apev2_size, fp) != apev2_size) {
4550 trace ("cmp3_write_metadata: failed to read original apev2 tag from %s\n", pl_find_meta (it, ":URI"));
4551 free (buf);
4552 goto error;
4553 }
4554 if (write (out, buf, apev2_size) != apev2_size) {
4555 trace ("cmp3_write_metadata: failed to copy original apev2 tag from %s to temp file\n", pl_find_meta (it, ":URI"));
4556 free (buf);
4557 goto error;
4558 }
4559 free (buf);
4560 }
4561 else if (write_apev2) {
4562 trace ("writing new apev2 tag (strip=%d)\n", strip_apev2);
4563 if (strip_apev2 || junk_apev2_read_full (NULL, &apev2, fp) != 0) {
4564 deadbeef->junk_apev2_free (&apev2);
4565 memset (&apev2, 0, sizeof (apev2));
4566 }
4567
4568 // remove all text frames
4569 junk_apev2_remove_all_text_frames (&apev2);
4570
4571 // add all basic frames
4572 DB_metaInfo_t *meta = pl_get_metadata_head (it);
4573 while (meta) {
4574 if (meta->value && *meta->value) {
4575 int i;
4576 for (i = 0; frame_mapping[i]; i += FRAME_MAPPINGS) {
4577 if (!strcasecmp (meta->key, frame_mapping[i+MAP_DDB]) && frame_mapping[i+MAP_APEV2]) {
4578 trace ("apev2 writing known field: %s=%s\n", meta->key, meta->value);
4579 junk_apev2_add_text_frame (&apev2, frame_mapping[i+MAP_APEV2], meta->value);
4580 break;
4581 }
4582 }
4583 if (!frame_mapping[i]
4584 && meta->key[0] != ':'
4585 && strcasecmp (meta->key, "track")
4586 && strcasecmp (meta->key, "numtracks")
4587 && strcasecmp (meta->key, "disc")
4588 && strcasecmp (meta->key, "numdiscs")
4589 ) {
4590 trace ("apev2 writing unknown field: %s=%s\n", meta->key, meta->value);
4591 junk_apev2_add_text_frame (&apev2, meta->key, meta->value);
4592 }
4593 }
4594 meta = meta->next;
4595 }
4596
4597 {
4598 pl_lock ();
4599 // add tracknumber/totaltracks
4600 const char *track = pl_find_meta (it, "track");
4601 const char *totaltracks = pl_find_meta (it, "numtracks");
4602 if (track && totaltracks) {
4603 char s[100];
4604 snprintf (s, sizeof (s), "%s/%s", track, totaltracks);
4605 junk_apev2_remove_frames (&apev2, "Track");
4606 junk_apev2_add_text_frame (&apev2, "Track", s);
4607 }
4608 else if (track) {
4609 junk_apev2_remove_frames (&apev2, "Track");
4610 junk_apev2_add_text_frame (&apev2, "Track", track);
4611 }
4612 // add discnumber/totaldiscs
4613 const char *disc = pl_find_meta (it, "disc");
4614 const char *totaldiscs = pl_find_meta (it, "numdiscs");
4615 if (disc && totaldiscs) {
4616 char s[100];
4617 snprintf (s, sizeof (s), "%s/%s", disc, totaldiscs);
4618 junk_apev2_remove_frames (&apev2, "disc");
4619 junk_apev2_add_text_frame (&apev2, "disc", s);
4620 }
4621 else if (disc) {
4622 junk_apev2_remove_frames (&apev2, "disc");
4623 junk_apev2_add_text_frame (&apev2, "disc", disc);
4624 }
4625 pl_unlock ();
4626 }
4627
4628 // remove and re-add replaygain apev2 frames
4629 for (int n = 0; ddb_internal_rg_keys[n]; n++) {
4630 junk_apev2_remove_frames (&apev2, tag_rg_names[n]);
4631 if (pl_find_meta (it, ddb_internal_rg_keys[0])) {
4632 float value = pl_get_item_replaygain (it, n);
4633 char s[100];
4634 snprintf (s, sizeof (s), "%f", value);
4635 junk_apev2_add_text_frame (&apev2, tag_rg_names[n], s);
4636 }
4637 }
4638
4639 // write tag
4640 if (junk_apev2_write2 (out, &apev2, 0, 1) != 0) {
4641 trace ("cmp3_write_metadata: failed to write apev2 tag to %s\n", pl_find_meta (it, ":URI"))
4642 goto error;
4643 }
4644 }
4645
4646 if (!write_id3v1 && !strip_id3v1 && id3v1_start != 0) {
4647 trace ("copying original id3v1 tag %d %d %d\n", write_id3v1, strip_id3v1, id3v1_start);
4648 if (deadbeef->fseek (fp, id3v1_start, SEEK_SET) == -1) {
4649 trace ("cmp3_write_metadata: failed to seek to original id3v1 tag position in %s\n", pl_find_meta (it, ":URI"));
4650 goto error;
4651 }
4652 char buf[128];
4653 if (deadbeef->fread (buf, 1, 128, fp) != 128) {
4654 trace ("cmp3_write_metadata: failed to read original id3v1 tag from %s\n", pl_find_meta (it, ":URI"));
4655 goto error;
4656 }
4657 if (write (out, buf, 128) != 128) {
4658 trace ("cmp3_write_metadata: failed to copy id3v1 tag from %s to temp file\n", pl_find_meta (it, ":URI"));
4659 goto error;
4660 }
4661 }
4662 else if (write_id3v1) {
4663 trace ("writing new id3v1 tag\n");
4664 if (junk_id3v1_write2 (out, it, id3v1_encoding) != 0) {
4665 trace ("cmp3_write_metadata: failed to write id3v1 tag to %s\n", pl_find_meta (it, ":URI"))
4666 goto error;
4667 }
4668 }
4669
4670 if (strip_id3v1 && !write_id3v1) {
4671 item_flags &= ~DDB_TAG_ID3V1;
4672 }
4673 if (strip_id3v2 && !write_id3v2) {
4674 item_flags &= ~(DDB_TAG_ID3V22|DDB_TAG_ID3V23|DDB_TAG_ID3V24);
4675 }
4676 if (strip_apev2 && !write_apev2) {
4677 item_flags &= ~DDB_TAG_APEV2;
4678 }
4679
4680 if (write_id3v1) {
4681 item_flags |= DDB_TAG_ID3V1;
4682 }
4683 if (write_id3v2) {
4684 item_flags &= ~(DDB_TAG_ID3V22|DDB_TAG_ID3V23|DDB_TAG_ID3V24);
4685 item_flags |= id3v2_version == 3 ? DDB_TAG_ID3V23 : DDB_TAG_ID3V24;
4686 }
4687 if (write_apev2) {
4688 item_flags |= DDB_TAG_APEV2;
4689 }
4690
4691 pl_set_item_flags (it, item_flags);
4692 err = 0;
4693 error:
4694 if (fp) {
4695 deadbeef->fclose (fp);
4696 }
4697 if (out) {
4698 close (out);
4699 out = -1;
4700 }
4701 if (buffer) {
4702 free (buffer);
4703 }
4704 if (!err) {
4705 pl_lock ();
4706 rename (tmppath, fname);
4707 pl_unlock ();
4708 }
4709 else {
4710 unlink (tmppath);
4711 }
4712 return err;
4713 }
4714
4715 void
junk_enable_cp1251_detection(int enable)4716 junk_enable_cp1251_detection (int enable) {
4717 enable_cp1251_detection = enable;
4718 }
4719
4720 void
junk_enable_cp936_detection(int enable)4721 junk_enable_cp936_detection (int enable) {
4722 enable_cp936_detection = enable;
4723 }
4724
4725 void
junk_enable_shift_jis_detection(int enable)4726 junk_enable_shift_jis_detection (int enable) {
4727 enable_shift_jis_detection = enable;
4728 }
4729
4730 void
junk_configchanged(void)4731 junk_configchanged (void) {
4732 int cp1251 = conf_get_int ("junk.enable_cp1251_detection", 1);
4733 int cp936 = conf_get_int ("junk.enable_cp936_detection", 0);
4734 int shift_jis = conf_get_int ("junk.enable_shift_jis_detection", 0);
4735 junk_enable_cp1251_detection (cp1251);
4736 junk_enable_cp936_detection (cp936);
4737 junk_enable_shift_jis_detection (shift_jis);
4738 }
4739