~ubuntu-branches/debian/sid/gmtp/sid

« back to all changes in this revision

Viewing changes to metatag_info.c

  • Committer: Bazaar Package Importer
  • Author(s): Alessio Treglia
  • Date: 2011-01-24 17:21:38 UTC
  • mfrom: (1.1.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20110124172138-30ssabr3ki093ji8
Tags: 0.8-1
* New upstream release.
* Refresh patches.
* Update debian/copyright.
* Add patch to improve the Italian translation.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * File:   metatag_info.c
3
 
 * Author: darran
4
 
 *
5
 
 * Created on November 11, 2010, 8:54 PM
6
 
 */
7
 
 
8
 
#include "config.h"
9
 
 
10
 
#include <gtk/gtk.h>
11
 
#include <glib.h>
12
 
#include <glib/gprintf.h>
13
 
#include <gconf/gconf.h>
14
 
#include <gconf/gconf-client.h>
15
 
#include <libmtp.h>
16
 
#include <libgen.h>
17
 
#include <sys/stat.h>
18
 
#include <strings.h>
19
 
#include <string.h>
20
 
#include <id3tag.h>
21
 
#include <stdio.h>
22
 
#include <FLAC/all.h>
23
 
#include <vorbis/vorbisfile.h>
24
 
 
25
 
#include "main.h"
26
 
#include "callbacks.h"
27
 
#include "interface.h"
28
 
#include "mtp.h"
29
 
#include "prefs.h"
30
 
#include "dnd.h"
31
 
#include "metatag_info.h"
32
 
 
33
 
gchar * ID3_getFrameText(struct id3_tag *tag, char *frame_name)
34
 
{
35
 
    const id3_ucs4_t *id3_string;
36
 
    struct id3_frame *id3_frame;
37
 
    union id3_field *id3_field;
38
 
    gchar *rtn_string = NULL;
39
 
    enum id3_field_textencoding id3_field_encoding = ID3_FIELD_TEXTENCODING_ISO_8859_1;
40
 
 
41
 
    id3_frame = id3_tag_findframe (tag, frame_name, 0);
42
 
    if (id3_frame == NULL)
43
 
        return NULL;
44
 
 
45
 
    id3_field = id3_frame_field (id3_frame, 0);
46
 
    if (id3_field && (id3_field_type (id3_field) == ID3_FIELD_TYPE_TEXTENCODING)) {
47
 
        id3_field_encoding = id3_field->number.value;
48
 
    }
49
 
    if (frame_name == ID3_FRAME_COMMENT){
50
 
        id3_field = id3_frame_field (id3_frame, 3);
51
 
    } else {
52
 
        id3_field = id3_frame_field (id3_frame, 1);
53
 
    }
54
 
    if (id3_field == NULL)
55
 
        return NULL;
56
 
    if (frame_name == ID3_FRAME_COMMENT){
57
 
        id3_string = id3_field_getfullstring (id3_field);
58
 
    } else {
59
 
        id3_string = id3_field_getstrings (id3_field, 0);
60
 
    }
61
 
    if (id3_string == NULL)
62
 
        return NULL;
63
 
    if (frame_name == ID3_FRAME_GENRE)
64
 
        id3_string = id3_genre_name (id3_string);
65
 
    if (id3_field_encoding == ID3_FIELD_TEXTENCODING_ISO_8859_1) {
66
 
        rtn_string = (gchar *) id3_ucs4_latin1duplicate (id3_string);
67
 
    } else {
68
 
        rtn_string = (gchar *) id3_ucs4_utf8duplicate (id3_string);
69
 
    }
70
 
    return rtn_string;
71
 
}
72
 
 
73
 
void get_id3_tags(gchar *filename, LIBMTP_track_t *trackinformation){
74
 
    gchar * tracknumber = 0;
75
 
 
76
 
    struct id3_file * id3_file_id = id3_file_open(filename, ID3_FILE_MODE_READONLY);
77
 
    
78
 
    if(id3_file_id != NULL){
79
 
        // We have a valid file, so lets get some data.
80
 
        struct id3_tag* id3_tag_id = id3_file_tag(id3_file_id);
81
 
        // We have our tag data, so now cycle through the fields.
82
 
        trackinformation->album = ID3_getFrameText(id3_tag_id, ID3_FRAME_ALBUM);
83
 
        trackinformation->title = ID3_getFrameText(id3_tag_id, ID3_FRAME_TITLE);
84
 
        trackinformation->artist = ID3_getFrameText(id3_tag_id, ID3_FRAME_ARTIST);
85
 
        trackinformation->date = ID3_getFrameText(id3_tag_id, ID3_FRAME_YEAR);
86
 
        trackinformation->genre = ID3_getFrameText(id3_tag_id, ID3_FRAME_GENRE);
87
 
        
88
 
        tracknumber = ID3_getFrameText(id3_tag_id, ID3_FRAME_TRACK);
89
 
        if (tracknumber != 0){
90
 
            trackinformation->tracknumber = atoi(tracknumber);
91
 
        } else {
92
 
            trackinformation->tracknumber = 0;
93
 
        }
94
 
        //trackinformation->tracknumber = atoi(ID3_getFrameText(id3_tag_id, ID3_FRAME_TRACK));
95
 
 
96
 
        // Need below if the default artist field is NULL
97
 
        if(trackinformation->artist == NULL)
98
 
            trackinformation->artist = ID3_getFrameText(id3_tag_id, "TPE2");
99
 
        if(trackinformation->artist == NULL)
100
 
            trackinformation->artist = ID3_getFrameText(id3_tag_id, "TPE3");
101
 
        if(trackinformation->artist == NULL)
102
 
            trackinformation->artist = ID3_getFrameText(id3_tag_id, "TPE4");
103
 
        if(trackinformation->artist == NULL)
104
 
            trackinformation->artist = ID3_getFrameText(id3_tag_id, "TCOM");
105
 
        // Need this if using different Year field.
106
 
        if(trackinformation->date == NULL)
107
 
            trackinformation->date = ID3_getFrameText(id3_tag_id, "TDRC");
108
 
        // Close our file for reading the fields.
109
 
        id3_file_close(id3_file_id);
110
 
    }
111
 
}
112
 
 
113
 
gchar * OGG_getFieldText(const vorbis_comment *comments, const char *name){
114
 
    gchar ** file_comments;
115
 
    gchar ** comments_split;
116
 
    gint file_comments_count = 0;
117
 
    // We simple cycle through our comments, looking for our name, and return it's value;
118
 
 
119
 
    if(comments->comments > 0){
120
 
        file_comments = comments->user_comments;
121
 
        file_comments_count = comments->comments;
122
 
        while(file_comments_count--){
123
 
            // We have our comment, now see if it is what we are after?
124
 
            comments_split = g_strsplit(*file_comments, "=", 2);
125
 
            if(*comments_split != NULL){
126
 
                //if(name == NULL) g_printf("OGG_getFieldText - name\n");
127
 
                //if(*comments_split == NULL) g_printf("OGG_getFieldText - *comments_split\n");
128
 
                if(g_ascii_strcasecmp(name, *comments_split) == 0){
129
 
                    // We have our desrired tag, so return it to the user.
130
 
                    comments_split++;
131
 
                    return g_strdup(*comments_split);
132
 
                }
133
 
            }
134
 
            // Increment our pointers accordingly.
135
 
            file_comments++;
136
 
        }
137
 
    } else {
138
 
        // No comments, so return a NULL value;
139
 
        return NULL;
140
 
    }
141
 
    // We didn't find our key, so return NULL
142
 
    return NULL;
143
 
}
144
 
 
145
 
void get_ogg_tags(gchar *filename, LIBMTP_track_t *trackinformation){
146
 
    OggVorbis_File *mov_file = NULL;
147
 
    FILE *mfile;
148
 
    vorbis_comment *mov_file_comment = NULL;
149
 
    gchar * tracknumber = NULL;
150
 
    
151
 
    // Attempt to open the file, and init the OggVorbis_File struct for our file.
152
 
    // Yes I know about ov_fopen(), but Solaris 10 ships with vorbis 1.0.1 which
153
 
    // doesn't have this function.
154
 
    mfile = fopen(filename, "r");
155
 
    if (mfile == NULL)
156
 
        return;
157
 
 
158
 
    // Allocate memory to hold the OV file information.
159
 
    mov_file = g_malloc0(sizeof(OggVorbis_File));
160
 
    
161
 
    if (ov_open(mfile, mov_file, NULL, 0) != 0 ){
162
 
        fclose(mfile);
163
 
        return;
164
 
    }
165
 
 
166
 
    // Get or comment data;
167
 
    mov_file_comment = ov_comment(mov_file, -1);
168
 
 
169
 
    trackinformation->album = OGG_getFieldText(mov_file_comment, "ALBUM");
170
 
    trackinformation->title = OGG_getFieldText(mov_file_comment, "TITLE");
171
 
    trackinformation->artist = OGG_getFieldText(mov_file_comment, "ARTIST");
172
 
    trackinformation->date = OGG_getFieldText(mov_file_comment, "DATE");
173
 
    trackinformation->genre = OGG_getFieldText(mov_file_comment, "GENRE");
174
 
    tracknumber = OGG_getFieldText(mov_file_comment, "TRACKNUMBER");
175
 
    if (tracknumber != NULL) {
176
 
        trackinformation->tracknumber = atoi(tracknumber);
177
 
    } else {
178
 
        trackinformation->tracknumber = 0;
179
 
    }
180
 
    
181
 
    ov_clear(mov_file);
182
 
     
183
 
    return;
184
 
}
185
 
 
186
 
gchar *FLAC_getFieldText(const FLAC__StreamMetadata *tags, const char *name){
187
 
 
188
 
    int index = FLAC__metadata_object_vorbiscomment_find_entry_from(tags, 0, name);
189
 
 
190
 
    if (index < 0 ){
191
 
        return NULL;
192
 
    }
193
 
    else {
194
 
        return strchr((const char *)tags->data.vorbis_comment.comments[index].entry, '=')+1;
195
 
    }
196
 
}
197
 
 
198
 
void get_flac_tags(gchar *filename, LIBMTP_track_t *trackinformation){
199
 
    FLAC__StreamMetadata *tags = NULL;
200
 
    gchar * tracknumber = 0;
201
 
    
202
 
    // Load in our tag information stream
203
 
    if(!FLAC__metadata_get_tags(filename, &tags))
204
 
        return;
205
 
    // We have our tag data, get the individual fields.
206
 
    trackinformation->album = g_strdup(FLAC_getFieldText(tags, "ALBUM"));
207
 
    trackinformation->title = g_strdup(FLAC_getFieldText(tags, "TITLE"));
208
 
    trackinformation->artist = g_strdup(FLAC_getFieldText(tags, "ARTIST"));
209
 
    trackinformation->date = g_strdup(FLAC_getFieldText(tags, "DATE"));
210
 
    trackinformation->genre = g_strdup(FLAC_getFieldText(tags, "GENRE"));
211
 
 
212
 
    tracknumber = FLAC_getFieldText(tags, "TRACKNUMBER");
213
 
    if (tracknumber != 0){
214
 
        trackinformation->tracknumber = atoi(tracknumber);
215
 
    } else {
216
 
        trackinformation->tracknumber = 0;
217
 
    }
218
 
    //trackinformation->tracknumber = atoi(FLAC_getFieldText(tags, "TRACKNUMBER"));
219
 
    FLAC__metadata_object_delete(tags);
220
 
    return;
221
 
}
222
 
 
223
 
void get_asf_tags(gchar *filename, LIBMTP_track_t *trackinformation){
224
 
    FILE *ASF_File;
225
 
    GUID Header_GUID ;
226
 
    uint32_t Header_Blocks;
227
 
    uint64_t Object_Size;
228
 
    long ASF_File_Position;
229
 
 
230
 
    // Content Object
231
 
    uint16_t Title_Length = 0;
232
 
    uint16_t Author_Length = 0;
233
 
    uint16_t Copyright_Length = 0;
234
 
    uint16_t Description_Length = 0;
235
 
    uint16_t Rating_Length = 0;
236
 
        
237
 
    gchar *Title = NULL;
238
 
    gchar *Author = NULL;
239
 
 
240
 
    // Extended Content Object
241
 
    uint16_t Content_Descriptors_Count = 0;
242
 
    uint16_t Descriptor_Name_Length = 0;
243
 
    gchar *Descriptor_Name = NULL;
244
 
    gchar *Descriptor_Name_UTF16 = NULL;
245
 
    uint16_t Descriptor_Value_Type = 0;
246
 
    uint16_t Descriptor_Value_Length = 0;
247
 
    uint64_t Descriptor_Value = 0;
248
 
    gchar *Descriptor_Value_Str = NULL;
249
 
    gchar *Descriptor_Value_Str_UTF16 = NULL;
250
 
 
251
 
 
252
 
    ASF_File = fopen(filename, "r");
253
 
    if (ASF_File == NULL)
254
 
        return;
255
 
 
256
 
    // Get our header GUID and make sure this is it.
257
 
    fread(&Header_GUID, sizeof(GUID), 1, ASF_File);
258
 
    if(!memcmp(&Header_GUID, &ASF_header, sizeof(GUID))){
259
 
        // If not exit.
260
 
        fclose(ASF_File);
261
 
        return;
262
 
    }
263
 
    // Skip the rest of the header area;
264
 
    fseek(ASF_File, 8, SEEK_CUR);
265
 
    fread(&Header_Blocks, sizeof(uint32_t), 1, ASF_File);
266
 
    fseek(ASF_File, 2, SEEK_CUR);
267
 
 
268
 
    // We should be at the start of the header blocks;
269
 
    // Header_blocks has the number of header objects that we can test.
270
 
    while(Header_Blocks--){
271
 
        fread(&Header_GUID, sizeof(GUID), 1, ASF_File);
272
 
        if(memcmp(&Header_GUID, &ASF_comment_header, sizeof(GUID)) == 0){
273
 
            // We have our standard comment header block;
274
 
            //g_printf("WMA: Found our comment block\n");
275
 
            // Get the size of the object, and the current file position.
276
 
            fread(&Object_Size, sizeof(uint64_t), 1, ASF_File);
277
 
            ASF_File_Position = ftell(ASF_File);
278
 
            // Get our field lengths.
279
 
            fread(&Title_Length, sizeof(uint16_t), 1, ASF_File);
280
 
            fread(&Author_Length, sizeof(uint16_t), 1, ASF_File);
281
 
            fread(&Copyright_Length, sizeof(uint16_t), 1, ASF_File);
282
 
            fread(&Description_Length, sizeof(uint16_t), 1, ASF_File);
283
 
            fread(&Rating_Length, sizeof(uint16_t), 1, ASF_File);
284
 
            // Since we only need Title and Author, we only need to alloc memory for those two.
285
 
            Title = g_malloc0(Title_Length + 0x10);
286
 
            Author = g_malloc0(Author_Length + 0x10);
287
 
            fread(Title, Title_Length, 1, ASF_File);
288
 
            fread(Author, Author_Length, 1, ASF_File);
289
 
            // Set our track information
290
 
            trackinformation->title = g_utf16_to_utf8 ((const gunichar2 *) Title, Title_Length, NULL, NULL, NULL );
291
 
            trackinformation->artist = g_utf16_to_utf8 ((const gunichar2 *) Author, Author_Length, NULL, NULL, NULL );
292
 
            // Free our memory that we used to load in the fields.
293
 
            g_free(Title);
294
 
            g_free(Author);
295
 
            Title = NULL;
296
 
            Author = NULL;
297
 
            // Set our file position so it's ready to read in the next GUID Header.
298
 
            fseek(ASF_File, ASF_File_Position, SEEK_SET);
299
 
            fseek(ASF_File, (Object_Size - sizeof(uint64_t) - sizeof(GUID)), SEEK_CUR);
300
 
        } else {
301
 
            if(memcmp(&Header_GUID, &ASF_extended_content_header, sizeof(GUID)) == 0){
302
 
                // We have our standard comment header block;
303
 
                //g_printf("WMA: Found our extended comment block\n");
304
 
                // Get the size of the object, and the current file position.
305
 
                fread(&Object_Size, sizeof(uint64_t), 1, ASF_File);
306
 
                ASF_File_Position = ftell(ASF_File);
307
 
                // Get the number of Descripions field we have, as we will need to cycle through them all.
308
 
                fread(&Content_Descriptors_Count, sizeof(uint16_t), 1, ASF_File);
309
 
                while(Content_Descriptors_Count--){
310
 
                    // These themselves are Objects within the main extended content header, which we need to handle.
311
 
                    // Format is:
312
 
                    // Descriptor Name Length (word)
313
 
                    // Descriptor Name (varies)
314
 
                    // Descriptor Value Type (word)
315
 
                    // Descriptor Value Length (word)
316
 
                    // Descriptor Value (varies - depend on Value Type).
317
 
                    Descriptor_Name_Length = 0;
318
 
                    Descriptor_Name = NULL;
319
 
                    Descriptor_Name_UTF16 = NULL;
320
 
                    Descriptor_Value_Type = 0;
321
 
                    Descriptor_Value_Length = 0;
322
 
                    Descriptor_Value = 0;
323
 
                    Descriptor_Value_Str = NULL;
324
 
                    Descriptor_Value_Str_UTF16 = NULL;
325
 
                    // Get our Descriptor Name.
326
 
                    fread(&Descriptor_Name_Length, sizeof(uint16_t), 1, ASF_File);
327
 
                    Descriptor_Name_UTF16 = g_malloc0(Descriptor_Name_Length + 0x10);
328
 
                    fread(Descriptor_Name_UTF16, Descriptor_Name_Length, 1, ASF_File);
329
 
                    Descriptor_Name = g_utf16_to_utf8 ((const gunichar2 *) Descriptor_Name_UTF16, Descriptor_Name_Length, NULL, NULL, NULL );
330
 
                    // Get our Value Type and Value Length
331
 
                    fread(&Descriptor_Value_Type, sizeof(uint16_t), 1, ASF_File);
332
 
                    fread(&Descriptor_Value_Length, sizeof(uint16_t), 1, ASF_File);
333
 
                    switch(Descriptor_Value_Type){
334
 
                        case 0: // String;
335
 
                        case 1: // Binary;
336
 
                            Descriptor_Value_Str_UTF16 = g_malloc0(Descriptor_Value_Length + 0x10);
337
 
                            fread(Descriptor_Value_Str_UTF16, Descriptor_Value_Length, 1, ASF_File);
338
 
                            Descriptor_Value_Str = g_utf16_to_utf8 ((const gunichar2 *) Descriptor_Value_Str_UTF16, Descriptor_Value_Length, NULL, NULL, NULL );
339
 
                            // We have out key=value pair so lets look for our desired  keys 'WM/AlbumTitle', 'WM/Genre' and 'WM/Year'
340
 
                            if(g_ascii_strcasecmp(Descriptor_Name, "WM/AlbumTitle\0") == 0){
341
 
                                // We have the album Title;
342
 
                                trackinformation->album = g_strdup(Descriptor_Value_Str);
343
 
                            } else {
344
 
                                if(g_ascii_strcasecmp(Descriptor_Name, "WM/Genre\0") == 0){
345
 
                                    // We have the album Genre;
346
 
                                    trackinformation->genre = g_strdup(Descriptor_Value_Str);
347
 
                                } else {
348
 
                                    if(g_ascii_strcasecmp(Descriptor_Name, "WM/Year\0") == 0){
349
 
                                        // We have the album Year;
350
 
                                        trackinformation->date = g_strdup(Descriptor_Value_Str);
351
 
                                    }
352
 
                                }
353
 
                            }
354
 
                            break;
355
 
                        case 2: // Boolean (DWORD)
356
 
                        case 3: // DWORD
357
 
                        case 4: // QWORD
358
 
                        case 5: // WORD
359
 
                            fread(&Descriptor_Value, Descriptor_Value_Length, 1, ASF_File);
360
 
                            if((g_ascii_strcasecmp(Descriptor_Name, "WM/Track\0") == 0)){
361
 
                                trackinformation->tracknumber = Descriptor_Value + 1;
362
 
                            } else {
363
 
                                if (g_ascii_strcasecmp(Descriptor_Name, "WM/TrackNumber\0") == 0)
364
 
                                    trackinformation->tracknumber = Descriptor_Value;
365
 
                            }
366
 
                            break;
367
 
                        default: // Unknown so skip it.
368
 
                            fseek(ASF_File, Descriptor_Value_Length, SEEK_CUR);
369
 
                            break;
370
 
                    }
371
 
 
372
 
                    // Free up our allocated memory;
373
 
                    g_free(Descriptor_Name);
374
 
                    g_free(Descriptor_Name_UTF16);
375
 
                    g_free(Descriptor_Value_Str);
376
 
                    g_free(Descriptor_Value_Str_UTF16);
377
 
                }
378
 
 
379
 
                // Set our file position so it's ready to read in the next GUID Header.
380
 
                fseek(ASF_File, ASF_File_Position, SEEK_SET);
381
 
                fseek(ASF_File, (Object_Size - sizeof(uint64_t) - sizeof(GUID)), SEEK_CUR);
382
 
            } else {
383
 
                // Skip this header;
384
 
                //g_printf("WMA: Unknown GUID - skipping\n");
385
 
                fread(&Object_Size, sizeof(uint64_t), 1, ASF_File);
386
 
                fseek(ASF_File, (Object_Size - sizeof(uint64_t) - sizeof(GUID)), SEEK_CUR);
387
 
            }
388
 
        }
389
 
 
390
 
    }
391
 
    fclose(ASF_File);
392
 
    return;
393
 
}