5
* Created on November 11, 2010, 8:54 PM
12
#include <glib/gprintf.h>
13
#include <gconf/gconf.h>
14
#include <gconf/gconf-client.h>
23
#include <vorbis/vorbisfile.h>
26
#include "callbacks.h"
27
#include "interface.h"
31
#include "metatag_info.h"
33
gchar * ID3_getFrameText(struct id3_tag *tag, char *frame_name)
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;
41
id3_frame = id3_tag_findframe (tag, frame_name, 0);
42
if (id3_frame == NULL)
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;
49
if (frame_name == ID3_FRAME_COMMENT){
50
id3_field = id3_frame_field (id3_frame, 3);
52
id3_field = id3_frame_field (id3_frame, 1);
54
if (id3_field == NULL)
56
if (frame_name == ID3_FRAME_COMMENT){
57
id3_string = id3_field_getfullstring (id3_field);
59
id3_string = id3_field_getstrings (id3_field, 0);
61
if (id3_string == 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);
68
rtn_string = (gchar *) id3_ucs4_utf8duplicate (id3_string);
73
void get_id3_tags(gchar *filename, LIBMTP_track_t *trackinformation){
74
gchar * tracknumber = 0;
76
struct id3_file * id3_file_id = id3_file_open(filename, ID3_FILE_MODE_READONLY);
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);
88
tracknumber = ID3_getFrameText(id3_tag_id, ID3_FRAME_TRACK);
89
if (tracknumber != 0){
90
trackinformation->tracknumber = atoi(tracknumber);
92
trackinformation->tracknumber = 0;
94
//trackinformation->tracknumber = atoi(ID3_getFrameText(id3_tag_id, ID3_FRAME_TRACK));
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);
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;
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.
131
return g_strdup(*comments_split);
134
// Increment our pointers accordingly.
138
// No comments, so return a NULL value;
141
// We didn't find our key, so return NULL
145
void get_ogg_tags(gchar *filename, LIBMTP_track_t *trackinformation){
146
OggVorbis_File *mov_file = NULL;
148
vorbis_comment *mov_file_comment = NULL;
149
gchar * tracknumber = NULL;
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");
158
// Allocate memory to hold the OV file information.
159
mov_file = g_malloc0(sizeof(OggVorbis_File));
161
if (ov_open(mfile, mov_file, NULL, 0) != 0 ){
166
// Get or comment data;
167
mov_file_comment = ov_comment(mov_file, -1);
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);
178
trackinformation->tracknumber = 0;
186
gchar *FLAC_getFieldText(const FLAC__StreamMetadata *tags, const char *name){
188
int index = FLAC__metadata_object_vorbiscomment_find_entry_from(tags, 0, name);
194
return strchr((const char *)tags->data.vorbis_comment.comments[index].entry, '=')+1;
198
void get_flac_tags(gchar *filename, LIBMTP_track_t *trackinformation){
199
FLAC__StreamMetadata *tags = NULL;
200
gchar * tracknumber = 0;
202
// Load in our tag information stream
203
if(!FLAC__metadata_get_tags(filename, &tags))
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"));
212
tracknumber = FLAC_getFieldText(tags, "TRACKNUMBER");
213
if (tracknumber != 0){
214
trackinformation->tracknumber = atoi(tracknumber);
216
trackinformation->tracknumber = 0;
218
//trackinformation->tracknumber = atoi(FLAC_getFieldText(tags, "TRACKNUMBER"));
219
FLAC__metadata_object_delete(tags);
223
void get_asf_tags(gchar *filename, LIBMTP_track_t *trackinformation){
226
uint32_t Header_Blocks;
227
uint64_t Object_Size;
228
long ASF_File_Position;
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;
238
gchar *Author = NULL;
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;
252
ASF_File = fopen(filename, "r");
253
if (ASF_File == NULL)
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))){
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);
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.
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);
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.
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){
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);
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);
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);
355
case 2: // Boolean (DWORD)
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;
363
if (g_ascii_strcasecmp(Descriptor_Name, "WM/TrackNumber\0") == 0)
364
trackinformation->tracknumber = Descriptor_Value;
367
default: // Unknown so skip it.
368
fseek(ASF_File, Descriptor_Value_Length, SEEK_CUR);
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);
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);
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);