No issues found
Tool | Failure ID | Location | Function | Message | Data |
---|---|---|---|---|---|
clang-analyzer | no-output-found | tracker-media-art.c | Message(text='Unable to locate XML output from invoke-clang-analyzer') | None |
1 /*
2 * Copyright (C) 2008, Nokia <ivan.frade@nokia.com>
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18 */
19
20 #include "config.h"
21
22 #include <string.h>
23 #include <stdlib.h>
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <unistd.h>
27 #include <ctype.h>
28 #include <sys/types.h>
29 #include <utime.h>
30 #include <time.h>
31
32 #include <glib.h>
33 #include <glib/gprintf.h>
34 #include <glib/gstdio.h>
35 #include <gio/gio.h>
36
37 #include "tracker-file-utils.h"
38 #include "tracker-date-time.h"
39 #include "tracker-media-art.h"
40
41 static gboolean
42 media_art_strip_find_next_block (const gchar *original,
43 const gunichar open_char,
44 const gunichar close_char,
45 gint *open_pos,
46 gint *close_pos)
47 {
48 const gchar *p1, *p2;
49
50 if (open_pos) {
51 *open_pos = -1;
52 }
53
54 if (close_pos) {
55 *close_pos = -1;
56 }
57
58 p1 = g_utf8_strchr (original, -1, open_char);
59 if (p1) {
60 if (open_pos) {
61 *open_pos = p1 - original;
62 }
63
64 p2 = g_utf8_strchr (g_utf8_next_char (p1), -1, close_char);
65 if (p2) {
66 if (close_pos) {
67 *close_pos = p2 - original;
68 }
69
70 return TRUE;
71 }
72 }
73
74 return FALSE;
75 }
76
77 /**
78 * tracker_media_art_strip_invalid_entities:
79 * @original: original string
80 *
81 * Strip a albumname or artistname string to prepare it for calculating the
82 * media art path with it. Certain characters and charactersets will be stripped
83 * and a newly allocated string returned which you must free with g_free.
84 *
85 * Returns: copy of original but then stripped
86 *
87 * Since: 0.10.14
88 */
89 gchar *
90 tracker_media_art_strip_invalid_entities (const gchar *original)
91 {
92 GString *str_no_blocks;
93 gchar **strv;
94 gchar *str;
95 gboolean blocks_done = FALSE;
96 const gchar *p;
97 const gchar *invalid_chars = "()[]<>{}_!@#$^&*+=|\\/\"'?~";
98 const gchar *invalid_chars_delimiter = "*";
99 const gchar *convert_chars = "\t";
100 const gchar *convert_chars_delimiter = " ";
101 const gunichar blocks[5][2] = {
102 { '(', ')' },
103 { '{', '}' },
104 { '[', ']' },
105 { '<', '>' },
106 { 0, 0 }
107 };
108
109 str_no_blocks = g_string_new ("");
110
111 p = original;
112
113 while (!blocks_done) {
114 gint pos1, pos2, i;
115
116 pos1 = -1;
117 pos2 = -1;
118
119 for (i = 0; blocks[i][0] != 0; i++) {
120 gint start, end;
121
122 /* Go through blocks, find the earliest block we can */
123 if (media_art_strip_find_next_block (p, blocks[i][0], blocks[i][1], &start, &end)) {
124 if (pos1 == -1 || start < pos1) {
125 pos1 = start;
126 pos2 = end;
127 }
128 }
129 }
130
131 /* If either are -1 we didn't find any */
132 if (pos1 == -1) {
133 /* This means no blocks were found */
134 g_string_append (str_no_blocks, p);
135 blocks_done = TRUE;
136 } else {
137 /* Append the test BEFORE the block */
138 if (pos1 > 0) {
139 g_string_append_len (str_no_blocks, p, pos1);
140 }
141
142 p = g_utf8_next_char (p + pos2);
143
144 /* Do same again for position AFTER block */
145 if (*p == '\0') {
146 blocks_done = TRUE;
147 }
148 }
149 }
150
151 /* Now convert chars to lower case */
152 str = g_utf8_strdown (str_no_blocks->str, -1);
153 g_string_free (str_no_blocks, TRUE);
154
155 /* Now strip invalid chars */
156 g_strdelimit (str, invalid_chars, *invalid_chars_delimiter);
157 strv = g_strsplit (str, invalid_chars_delimiter, -1);
158 g_free (str);
159 str = g_strjoinv (NULL, strv);
160 g_strfreev (strv);
161
162 /* Now convert chars */
163 g_strdelimit (str, convert_chars, *convert_chars_delimiter);
164 strv = g_strsplit (str, convert_chars_delimiter, -1);
165 g_free (str);
166 str = g_strjoinv (convert_chars_delimiter, strv);
167 g_strfreev (strv);
168
169 while (g_strrstr (str, " ") != NULL) {
170 /* Now remove double spaces */
171 strv = g_strsplit (str, " ", -1);
172 g_free (str);
173 str = g_strjoinv (" ", strv);
174 g_strfreev (strv);
175 }
176
177 /* Now strip leading/trailing white space */
178 g_strstrip (str);
179
180 return str;
181 }
182
183 static gchar *
184 media_art_checksum_for_data (GChecksumType checksum_type,
185 const guchar *data,
186 gsize length)
187 {
188 GChecksum *checksum;
189 gchar *retval;
190
191 checksum = g_checksum_new (checksum_type);
192 if (!checksum) {
193 return NULL;
194 }
195
196 g_checksum_update (checksum, data, length);
197 retval = g_strdup (g_checksum_get_string (checksum));
198 g_checksum_free (checksum);
199
200 return retval;
201 }
202
203 /**
204 * tracker_media_art_get_path:
205 * @artist: the artist
206 * @title: the title
207 * @prefix: For example "album"
208 * @uri: NULL or the uri of the file
209 * @path: the location to store the local path
210 * @local_uri: the location to store the local uri or NULL
211 *
212 * Get the path to media art for a given resource. Newly allocated data in
213 * @path and @local_uri must be freed with g_free.
214 *
215 * Since: 0.10.14
216 */
217 void
218 tracker_media_art_get_path (const gchar *artist,
219 const gchar *title,
220 const gchar *prefix,
221 const gchar *uri,
222 gchar **path,
223 gchar **local_uri)
224 {
225 const gchar *space_checksum = "7215ee9c7d9dc229d2921a40e899ec5f";
226 const gchar *a, *b;
227
228 gchar *art_filename;
229 gchar *dir;
230 gchar *artist_down, *title_down;
231 gchar *artist_stripped, *title_stripped;
232 gchar *artist_norm, *title_norm;
233 gchar *artist_checksum = NULL, *title_checksum = NULL;
234
235 /* http://live.gnome.org/MediaArtStorageSpec */
236
237 if (path) {
238 *path = NULL;
239 }
240
241 if (local_uri) {
242 *local_uri = NULL;
243 }
244
245 if (!artist && !title) {
246 return;
247 }
248
249 if (artist) {
250 artist_stripped = tracker_media_art_strip_invalid_entities (artist);
251 artist_norm = g_utf8_normalize (artist_stripped, -1, G_NORMALIZE_NFKD);
252 artist_down = g_utf8_strdown (artist_norm, -1);
253 artist_checksum = media_art_checksum_for_data (G_CHECKSUM_MD5,
254 (const guchar *) artist_down,
255 strlen (artist_down));
256 }
257
258 if (title) {
259 title_stripped = tracker_media_art_strip_invalid_entities (title);
260 title_norm = g_utf8_normalize (title_stripped, -1, G_NORMALIZE_NFKD);
261 title_down = g_utf8_strdown (title_norm, -1);
262 title_checksum = media_art_checksum_for_data (G_CHECKSUM_MD5,
263 (const guchar *) title_down,
264 strlen (title_down));
265 }
266
267 dir = g_build_filename (g_get_user_cache_dir (),
268 "media-art",
269 NULL);
270
271 if (!g_file_test (dir, G_FILE_TEST_EXISTS)) {
272 g_mkdir_with_parents (dir, 0770);
273 }
274
275 if (artist) {
276 a = artist_checksum;
277 b = title ? title_checksum : space_checksum;
278 } else {
279 a = title_checksum;
280 b = space_checksum;
281 }
282
283 art_filename = g_strdup_printf ("%s-%s-%s.jpeg", prefix ? prefix : "album", a, b);
284
285 if (artist) {
286 g_free (artist_checksum);
287 g_free (artist_stripped);
288 g_free (artist_down);
289 g_free (artist_norm);
290 }
291
292 if (title) {
293 g_free (title_checksum);
294 g_free (title_stripped);
295 g_free (title_down);
296 g_free (title_norm);
297 }
298
299 if (path) {
300 *path = g_build_filename (dir, art_filename, NULL);
301 }
302
303 if (local_uri) {
304 gchar *local_dir;
305 GFile *file, *parent;
306
307 if (strstr (uri, "://")) {
308 file = g_file_new_for_uri (uri);
309 } else {
310 file = g_file_new_for_path (uri);
311 }
312
313 parent = g_file_get_parent (file);
314 if (parent) {
315 local_dir = g_file_get_uri (parent);
316
317 /* This is a URI, don't use g_build_filename here */
318 *local_uri = g_strdup_printf ("%s/.mediaartlocal/%s", local_dir, art_filename);
319
320 g_free (local_dir);
321 g_object_unref (parent);
322 }
323 g_object_unref (file);
324 }
325
326 g_free (dir);
327 g_free (art_filename);
328 }