1 /*
2   This file is part of Deadbeef Player source code
3   http://deadbeef.sourceforge.net
4 
5   playlist metadata management
6 
7   Copyright (C) 2009-2013 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 
28 #include <string.h>
29 #include <stdlib.h>
30 #include "playlist.h"
31 #include "deadbeef.h"
32 #include "metacache.h"
33 #include "pltmeta.h"
34 
35 #define LOCK {pl_lock();}
36 #define UNLOCK {pl_unlock();}
37 
38 void
plt_add_meta(playlist_t * it,const char * key,const char * value)39 plt_add_meta (playlist_t *it, const char *key, const char *value) {
40     LOCK;
41     // check if it's already set
42     DB_metaInfo_t *tail = NULL;
43     DB_metaInfo_t *m = it->meta;
44     while (m) {
45         if (!strcasecmp (key, m->key)) {
46             // duplicate key
47             UNLOCK;
48             return;
49         }
50         tail = m;
51         m = m->next;
52     }
53     // add
54     char str[256];
55     if (!value || !*value) {
56         UNLOCK;
57         return;
58     }
59     m = malloc (sizeof (DB_metaInfo_t));
60     memset (m, 0, sizeof (DB_metaInfo_t));
61     m->key = metacache_add_string (key); //key;
62     m->value = metacache_add_string (value); //strdup (value);
63 
64     if (tail) {
65         tail->next = m;
66     }
67     else {
68         it->meta = m;
69     }
70     UNLOCK;
71 }
72 
73 void
plt_append_meta(playlist_t * it,const char * key,const char * value)74 plt_append_meta (playlist_t *it, const char *key, const char *value) {
75     pl_lock ();
76     const char *old = plt_find_meta (it, key);
77     size_t newlen = strlen (value);
78     if (!old) {
79         plt_add_meta (it, key, value);
80     }
81     else {
82         // check for duplicate data
83         const char *str = old;
84         int len;
85         while (str) {
86             char *next = strchr (str, '\n');
87 
88             if (next) {
89                 len = next - str;
90                 next++;
91             }
92             else {
93                 len = strlen (str);
94             }
95 
96             if (len == newlen && !memcmp (str, value, len)) {
97                 pl_unlock ();
98                 return;
99             }
100 
101             str = next;
102         }
103         int sz = strlen (old) + newlen + 2;
104         char out[sz];
105         snprintf (out, sz, "%s\n%s", old, value);
106         plt_replace_meta (it, key, out);
107     }
108     pl_unlock ();
109 }
110 
111 void
plt_replace_meta(playlist_t * it,const char * key,const char * value)112 plt_replace_meta (playlist_t *it, const char *key, const char *value) {
113     LOCK;
114     // check if it's already set
115     DB_metaInfo_t *m = it->meta;
116     while (m) {
117         if (!strcasecmp (key, m->key)) {
118             break;
119         }
120         m = m->next;
121     }
122     if (m) {
123         metacache_remove_string (m->value);
124         m->value = metacache_add_string (value);
125         UNLOCK;
126         return;
127     }
128     else {
129         plt_add_meta (it, key, value);
130     }
131     UNLOCK;
132 }
133 
134 void
plt_set_meta_int(playlist_t * it,const char * key,int value)135 plt_set_meta_int (playlist_t *it, const char *key, int value) {
136     char s[20];
137     snprintf (s, sizeof (s), "%d", value);
138     plt_replace_meta (it, key, s);
139 }
140 
141 void
plt_set_meta_float(playlist_t * it,const char * key,float value)142 plt_set_meta_float (playlist_t *it, const char *key, float value) {
143     char s[20];
144     snprintf (s, sizeof (s), "%f", value);
145     plt_replace_meta (it, key, s);
146 }
147 
148 void
plt_delete_meta(playlist_t * it,const char * key)149 plt_delete_meta (playlist_t *it, const char *key) {
150     DB_metaInfo_t *prev = NULL;
151     DB_metaInfo_t *m = it->meta;
152     while (m) {
153         if (!strcasecmp (key, m->key)) {
154             if (prev) {
155                 prev->next = m->next;
156             }
157             else {
158                 it->meta = m->next;
159             }
160             metacache_remove_string (m->key);
161             metacache_remove_string (m->value);
162             free (m);
163             break;
164         }
165         prev = m;
166         m = m->next;
167     }
168 }
169 
170 const char *
plt_find_meta(playlist_t * it,const char * key)171 plt_find_meta (playlist_t *it, const char *key) {
172     DB_metaInfo_t *m = it->meta;
173     while (m) {
174         if (!strcasecmp (key, m->key)) {
175             return m->value;
176         }
177         m = m->next;
178     }
179     return NULL;
180 }
181 
182 int
plt_find_meta_int(playlist_t * it,const char * key,int def)183 plt_find_meta_int (playlist_t *it, const char *key, int def) {
184     pl_lock ();
185     const char *val = plt_find_meta (it, key);
186     int res = val ? atoi (val) : def;
187     pl_unlock ();
188     return res;
189 }
190 
191 float
plt_find_meta_float(playlist_t * it,const char * key,float def)192 plt_find_meta_float (playlist_t *it, const char *key, float def) {
193     pl_lock ();
194     const char *val = plt_find_meta (it, key);
195     float res = val ? atof (val) : def;
196     pl_unlock ();
197     return res;
198 }
199 
200 DB_metaInfo_t *
plt_get_metadata_head(playlist_t * it)201 plt_get_metadata_head (playlist_t *it) {
202     return it->meta;
203 }
204 
205 void
plt_delete_metadata(playlist_t * it,DB_metaInfo_t * meta)206 plt_delete_metadata (playlist_t *it, DB_metaInfo_t *meta) {
207     DB_metaInfo_t *prev = NULL;
208     DB_metaInfo_t *m = it->meta;
209     while (m) {
210         if (m == meta) {
211             if (prev) {
212                 prev->next = m->next;
213             }
214             else {
215                 it->meta = m->next;
216             }
217             metacache_remove_string (m->key);
218             metacache_remove_string (m->value);
219             free (m);
220             break;
221         }
222         prev = m;
223         m = m->next;
224     }
225 }
226 
227 
228 void
plt_delete_all_meta(playlist_t * it)229 plt_delete_all_meta (playlist_t *it) {
230     LOCK;
231     DB_metaInfo_t *m = it->meta;
232     DB_metaInfo_t *prev = NULL;
233     while (m) {
234         DB_metaInfo_t *next = m->next;
235         if (m->key[0] == ':') {
236             prev = m;
237         }
238         else {
239             if (prev) {
240                 prev->next = next;
241             }
242             else {
243                 it->meta = next;
244             }
245             metacache_remove_string (m->key);
246             metacache_remove_string (m->value);
247             free (m);
248         }
249         m = next;
250     }
251     UNLOCK;
252 }
253 
254 int
plt_get_meta(playlist_t * handle,const char * key,char * val,int size)255 plt_get_meta (playlist_t *handle, const char *key, char *val, int size) {
256     *val = 0;
257     LOCK;
258     const char *v = plt_find_meta (handle, key);
259     if (!v) {
260         UNLOCK;
261         return 0;
262     }
263     strncpy (val, v, size);
264     UNLOCK;
265     return 1;
266 }
267