aboutsummaryrefslogtreecommitdiff
path: root/src/plugins/id3_extractor.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/id3_extractor.c')
-rw-r--r--src/plugins/id3_extractor.c149
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
32typedef struct 34typedef 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
204struct id3_state
205{
206 int state;
207 id3tag info;
208};
209
210enum ID3State
211{
212 ID3_INVALID = -1,
213 ID3_SEEKING_TO_TAIL = 0,
214 ID3_READING_TAIL = 1
215};
216
217void
218EXTRACTOR_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
228void
229EXTRACTOR_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
202static void 244static void
203trim (char *k) 245trim (char *k)
204{ 246{
@@ -209,14 +251,14 @@ trim (char *k)
209} 251}
210 252
211static int 253static int
212get_id3 (const char *data, size_t size, id3tag * id3) 254get_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
259const char * 301int
260EXTRACTOR_id3_options () 302EXTRACTOR_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
266int 317 state = plugin->state;
267EXTRACTOR_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 }
292FINISH: 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 */