diff options
Diffstat (limited to 'src/plugins/id3_extractor.c')
-rw-r--r-- | src/plugins/id3_extractor.c | 149 |
1 files changed, 112 insertions, 37 deletions
diff --git a/src/plugins/id3_extractor.c b/src/plugins/id3_extractor.c index 64d341c..39bd779 100644 --- a/src/plugins/id3_extractor.c +++ b/src/plugins/id3_extractor.c | |||
@@ -29,6 +29,8 @@ | |||
29 | #include <unistd.h> | 29 | #include <unistd.h> |
30 | #include <stdlib.h> | 30 | #include <stdlib.h> |
31 | 31 | ||
32 | #include "extractor_plugins.h" | ||
33 | |||
32 | typedef struct | 34 | typedef struct |
33 | { | 35 | { |
34 | char *title; | 36 | char *title; |
@@ -199,6 +201,46 @@ static const char *const genre_names[] = { | |||
199 | #define OK 0 | 201 | #define OK 0 |
200 | #define INVALID_ID3 1 | 202 | #define INVALID_ID3 1 |
201 | 203 | ||
204 | struct id3_state | ||
205 | { | ||
206 | int state; | ||
207 | id3tag info; | ||
208 | }; | ||
209 | |||
210 | enum ID3State | ||
211 | { | ||
212 | ID3_INVALID = -1, | ||
213 | ID3_SEEKING_TO_TAIL = 0, | ||
214 | ID3_READING_TAIL = 1 | ||
215 | }; | ||
216 | |||
217 | void | ||
218 | EXTRACTOR_id3_init_state_method (struct EXTRACTOR_PluginList *plugin) | ||
219 | { | ||
220 | struct id3_state *state; | ||
221 | state = plugin->state = malloc (sizeof (struct id3_state)); | ||
222 | if (state == NULL) | ||
223 | return; | ||
224 | memset (state, 0, sizeof (struct id3_state)); | ||
225 | state->state = ID3_SEEKING_TO_TAIL; | ||
226 | } | ||
227 | |||
228 | void | ||
229 | EXTRACTOR_id3_discard_state_method (struct EXTRACTOR_PluginList *plugin) | ||
230 | { | ||
231 | struct id3_state *state = plugin->state; | ||
232 | if (state != NULL) | ||
233 | { | ||
234 | if (state->info.title != NULL) free (state->info.title); | ||
235 | if (state->info.year != NULL) free (state->info.year); | ||
236 | if (state->info.album != NULL) free (state->info.album); | ||
237 | if (state->info.artist != NULL) free (state->info.artist); | ||
238 | if (state->info.comment != NULL) free (state->info.comment); | ||
239 | free (state); | ||
240 | } | ||
241 | plugin->state = NULL; | ||
242 | } | ||
243 | |||
202 | static void | 244 | static void |
203 | trim (char *k) | 245 | trim (char *k) |
204 | { | 246 | { |
@@ -209,14 +251,14 @@ trim (char *k) | |||
209 | } | 251 | } |
210 | 252 | ||
211 | static int | 253 | static int |
212 | get_id3 (const char *data, size_t size, id3tag * id3) | 254 | get_id3 (const char *data, int64_t offset, int64_t size, id3tag *id3) |
213 | { | 255 | { |
214 | const char *pos; | 256 | const char *pos; |
215 | 257 | ||
216 | if (size < 128) | 258 | if (size < 128) |
217 | return INVALID_ID3; | 259 | return INVALID_ID3; |
218 | 260 | ||
219 | pos = &data[size - 128]; | 261 | pos = &data[offset]; |
220 | if (0 != strncmp ("TAG", pos, 3)) | 262 | if (0 != strncmp ("TAG", pos, 3)) |
221 | return INVALID_ID3; | 263 | return INVALID_ID3; |
222 | pos += 3; | 264 | pos += 3; |
@@ -253,49 +295,82 @@ get_id3 (const char *data, size_t size, id3tag * id3) | |||
253 | } | 295 | } |
254 | 296 | ||
255 | 297 | ||
256 | #define ADD(s,t) do { if ( (s != NULL) && (strlen(s) > 0) && (0 != (ret = proc (proc_cls, "id3", t, EXTRACTOR_METAFORMAT_UTF8, "text/plain", s, strlen(s)+1)))) goto FINISH; } while (0) | 298 | #define ADD(s,t) do { if ( (s != NULL) && (strlen(s) > 0) && (0 != proc (proc_cls, "id3", t, EXTRACTOR_METAFORMAT_UTF8, "text/plain", s, strlen(s)+1))) return 1; } while (0) |
257 | 299 | ||
258 | 300 | ||
259 | const char * | 301 | int |
260 | EXTRACTOR_id3_options () | 302 | EXTRACTOR_id3_extract_method (struct EXTRACTOR_PluginList *plugin, |
303 | EXTRACTOR_MetaDataProcessor proc, void *proc_cls) | ||
261 | { | 304 | { |
262 | return "want-tail"; | 305 | int64_t file_position; |
263 | } | 306 | int64_t file_size; |
307 | int64_t offset = 0; | ||
308 | int64_t size; | ||
309 | struct id3_state *state; | ||
310 | char *data; | ||
311 | |||
312 | char track[16]; | ||
264 | 313 | ||
314 | if (plugin == NULL || plugin->state == NULL) | ||
315 | return 1; | ||
265 | 316 | ||
266 | int | 317 | state = plugin->state; |
267 | EXTRACTOR_id3_extract (const char *data, | 318 | file_position = plugin->position; |
268 | size_t size, | 319 | file_size = plugin->fsize; |
269 | EXTRACTOR_MetaDataProcessor proc, | 320 | size = plugin->map_size; |
270 | void *proc_cls, | 321 | data = (char *) plugin->shm_ptr; |
271 | const char *options) | 322 | |
272 | { | 323 | if (plugin->seek_request < 0) |
273 | id3tag info; | 324 | return 1; |
274 | char track[16]; | 325 | if (file_position - plugin->seek_request > 0) |
275 | int ret; | 326 | { |
327 | plugin->seek_request = -1; | ||
328 | return 1; | ||
329 | } | ||
330 | if (plugin->seek_request - file_position < size) | ||
331 | offset = plugin->seek_request - file_position; | ||
276 | 332 | ||
277 | ret = 0; | 333 | while (1) |
278 | if (OK != get_id3 (data, size, &info)) | 334 | { |
279 | return 0; | 335 | switch (state->state) |
280 | ADD (info.title, EXTRACTOR_METATYPE_TITLE); | ||
281 | ADD (info.artist, EXTRACTOR_METATYPE_ARTIST); | ||
282 | ADD (info.album, EXTRACTOR_METATYPE_ALBUM); | ||
283 | ADD (info.year, EXTRACTOR_METATYPE_PUBLICATION_YEAR); | ||
284 | ADD (info.genre, EXTRACTOR_METATYPE_GENRE); | ||
285 | ADD (info.comment, EXTRACTOR_METATYPE_COMMENT); | ||
286 | if (info.track_number != 0) | ||
287 | { | 336 | { |
288 | snprintf(track, | 337 | case ID3_INVALID: |
289 | sizeof(track), "%u", info.track_number); | 338 | plugin->seek_request = -1; |
290 | ADD (track, EXTRACTOR_METATYPE_TRACK_NUMBER); | 339 | return 1; |
340 | case ID3_SEEKING_TO_TAIL: | ||
341 | offset = file_size - 128 - file_position; | ||
342 | if (offset > size) | ||
343 | { | ||
344 | state->state = ID3_READING_TAIL; | ||
345 | plugin->seek_request = file_position + offset; | ||
346 | return 0; | ||
347 | } | ||
348 | else if (offset < 0) | ||
349 | { | ||
350 | state->state = ID3_INVALID; | ||
351 | break; | ||
352 | } | ||
353 | state->state = ID3_READING_TAIL; | ||
354 | break; | ||
355 | case ID3_READING_TAIL: | ||
356 | if (OK != get_id3 (data, offset, size - offset, &state->info)) | ||
357 | return 1; | ||
358 | ADD (state->info.title, EXTRACTOR_METATYPE_TITLE); | ||
359 | ADD (state->info.artist, EXTRACTOR_METATYPE_ARTIST); | ||
360 | ADD (state->info.album, EXTRACTOR_METATYPE_ALBUM); | ||
361 | ADD (state->info.year, EXTRACTOR_METATYPE_PUBLICATION_YEAR); | ||
362 | ADD (state->info.genre, EXTRACTOR_METATYPE_GENRE); | ||
363 | ADD (state->info.comment, EXTRACTOR_METATYPE_COMMENT); | ||
364 | if (state->info.track_number != 0) | ||
365 | { | ||
366 | snprintf(track, | ||
367 | sizeof(track), "%u", state->info.track_number); | ||
368 | ADD (track, EXTRACTOR_METATYPE_TRACK_NUMBER); | ||
369 | } | ||
370 | state->state = ID3_INVALID; | ||
291 | } | 371 | } |
292 | FINISH: | 372 | } |
293 | if (info.title != NULL) free (info.title); | 373 | return 1; |
294 | if (info.year != NULL) free (info.year); | ||
295 | if (info.album != NULL) free (info.album); | ||
296 | if (info.artist != NULL) free (info.artist); | ||
297 | if (info.comment != NULL) free (info.comment); | ||
298 | return ret; | ||
299 | } | 374 | } |
300 | 375 | ||
301 | /* end of id3_extractor.c */ | 376 | /* end of id3_extractor.c */ |