tracker-0.16.2/src/libtracker-common/tracker-media-art.c

No issues found

Incomplete coverage

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
Failure running clang-analyzer ('no-output-found')
Message
Unable to locate XML output from invoke-clang-analyzer
  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 }