80d3be323b6a353a9d627dbf022c5676cf096414
[platform/core/api/metadata-editor.git] / src / metadata_editor.cpp
1 /*
2 * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <metadata_editor.h>
18 #include <metadata_editor_private.h>
19 #include <aul.h>
20 #include <sys/types.h>
21 #include <sys/stat.h>
22 #include <fcntl.h>
23 #include <unistd.h>
24 #include <glib.h>
25
26 #define MIME_TYPE_JPEG "image/jpeg"
27 #define MIME_TYPE_PNG "image/png"
28
29 static int __ID3_getTwixFrameByName(metadata_editor_s* _metadata, TagLib::ID3v1::Tag* tag1, TagLib::ID3v2::Tag* tag2, const char* frameID, char** value);
30 static int __ID3_setTwixFrameByName(metadata_editor_s* _metadata, TagLib::ID3v1::Tag* tag1, TagLib::ID3v2::Tag* tag2, const char* frameID, const char* value);
31 static int __ID3_getFrameByName(metadata_editor_s* _metadata, TagLib::ID3v2::Tag* tag2, const char* frameID, char** value);
32 static int __ID3_setFrameByName(metadata_editor_s* _metadata, TagLib::ID3v2::Tag* tag2, const char* frameID, const char* value);
33 static int __ID3_getLyricsFrame(metadata_editor_s* _metadata, TagLib::ID3v2::Tag* tag2, char** value);
34 static int __ID3_setTwixCommentFrame(metadata_editor_s* _metadata, TagLib::ID3v1::Tag* tag1, TagLib::ID3v2::Tag* tag2, const char* value);
35 static int __ID3_setLyricsFrame(metadata_editor_s* _metadata, TagLib::ID3v2::Tag* tag2, const char* value);
36 static int __MP4_getStringItem(metadata_editor_s* _metadata, const char* itemname, char** value);
37 static int __MP4_getIntegerItem(metadata_editor_s* _metadata, const char* itemname, char** value);
38 static int __MP4_updateStringItem(metadata_editor_s* _metadata, const char* itemname, const char* value);
39 static int __MP4_updateIntegerItem(metadata_editor_s* _metadata, const char* itemname, const char* value);
40 #if 0
41 static int __xiph_getFieldValue(metadata_editor_s* _metadata, TagLib::Ogg::XiphComment* xtag, const char* fieldname, char** value);
42 static int __xiph_updateFieldValue(metadata_editor_s* _metadata, TagLib::Ogg::XiphComment* xtag, const char* fieldname, const char* value);
43 #endif
44 typedef enum {
45         METADATA_EDITOR_FORMAT_MP3 = 0,                 /**< MP3 File */
46         METADATA_EDITOR_FORMAT_MP4,                             /**< MP4 File */
47         METADATA_EDITOR_FORMAT_FLAC,                            /**< FLAC File */
48         METADATA_EDITOR_FORMAT_OGG_VORBIS,                      /**< Vorbis Audio in Ogg container */
49         METADATA_EDITOR_FORMAT_OGG_FLAC,                        /**< FLAC Audio in Ogg container */
50         METADATA_EDITOR_FORMAT_WAV,                             /**< WAV file */
51         METADATA_EDITOR_FORMAT_NOTYPE = 0xFF            /**< Error type. File type is not correct or not specified */
52 } metadata_editor_format_e;
53
54 static int __check_metadata_parameter(metadata_editor_s *metadata)
55 {
56         metadata_editor_retvm_if(!metadata, METADATA_EDITOR_ERROR_INVALID_PARAMETER, "Invalid metadata");
57         metadata_editor_retvm_if(!metadata->file, METADATA_EDITOR_ERROR_INVALID_PARAMETER, "File loading fail");
58
59         return METADATA_EDITOR_ERROR_NONE;
60 }
61
62 static int __check_metadata_set_parameter(metadata_editor_s *metadata)
63 {
64         int ret = METADATA_EDITOR_ERROR_NONE;
65
66         ret = __check_metadata_parameter(metadata);
67         metadata_editor_retvm_if(ret != METADATA_EDITOR_ERROR_NONE, ret, "fail to __check_metadata_parameter");
68
69         metadata_editor_retvm_if(metadata->file->readOnly(), METADATA_EDITOR_ERROR_PERMISSION_DENIED, "File is readonly. Unable to modify");
70
71         return METADATA_EDITOR_ERROR_NONE;
72 }
73
74 static int __check_metadata_get_parameter(metadata_editor_s *metadata, char **value)
75 {
76         int ret = METADATA_EDITOR_ERROR_NONE;
77
78         ret = __check_metadata_parameter(metadata);
79         metadata_editor_retvm_if(ret != METADATA_EDITOR_ERROR_NONE, ret, "fail to __check_metadata_parameter");
80
81         metadata_editor_retvm_if(!value, METADATA_EDITOR_ERROR_INVALID_PARAMETER, "Invalid value");
82
83         return METADATA_EDITOR_ERROR_NONE;
84 }
85
86 static int __ID3_getTwixFrameByName(metadata_editor_s *_metadata, TagLib::ID3v1::Tag *tag1, TagLib::ID3v2::Tag *tag2, const char *frameID, char **value)
87 {
88         int ret = METADATA_EDITOR_ERROR_NONE;
89
90         ret = __check_metadata_get_parameter(_metadata, value);
91         metadata_editor_retvm_if(ret != METADATA_EDITOR_ERROR_NONE, ret, "fail to __check_metadata_get_parameter() [%d]", ret);
92         metadata_editor_retvm_if(!frameID, METADATA_EDITOR_ERROR_INVALID_PARAMETER, "Invalid frameID");
93
94         if (tag2 && !(tag2->frameListMap()[frameID].isEmpty())) {
95                 metadata_editor_info("The frame %s exists in ID3v2 tag", frameID);
96                 *value = g_strdup(tag2->frameListMap()[frameID][0]->toString().toCString(true));
97                 return METADATA_EDITOR_ERROR_NONE;
98         }
99
100         metadata_editor_info("The frame %s in ID3v2 tag is empty", frameID);
101
102         if (!tag1 || tag1->isEmpty()) {
103                 metadata_editor_info("The frame %s in ID3v1 tag is empty as well", frameID);
104                 return METADATA_EDITOR_ERROR_NONE;
105         }
106
107         metadata_editor_info("Reading data from ID3v1 tag");
108
109         if (!strcmp(frameID, "TPE1"))   /* artist */
110                 *value = g_strdup(tag1->artist().toCString(true));
111         else if (!strcmp(frameID, "TALB"))      /* album */
112                 *value = g_strdup(tag1->album().toCString(true));
113         else if (!strcmp(frameID, "COMM"))      /* comment */
114                 *value = g_strdup(tag1->comment().toCString(true));
115         else if (!strcmp(frameID, "TCON"))      /* genre */
116                 *value = g_strdup(tag1->genre().toCString(true));
117         else if (!strcmp(frameID, "TIT2"))      /* title */
118                 *value = g_strdup(tag1->title().toCString(true));
119         else if (!strcmp(frameID, "TRCK"))      /* track */
120                 *value = g_strdup_printf("%u", tag1->track());
121         else if (!strcmp(frameID, "TDRC"))      /* data (year) */
122                 *value = g_strdup_printf("%u", tag1->year());
123         else
124                 metadata_editor_debug("The desired frame was not found");
125
126         return METADATA_EDITOR_ERROR_NONE;
127 }
128
129
130 // *** This is an auxiliary function that is used to write the new value to the frame *** //
131 // *** It operates with frames that exists both in ID3v1 and ID3v2 tags *** //
132 static int __ID3_setTwixFrameByName(metadata_editor_s* _metadata, TagLib::ID3v1::Tag* tag1, TagLib::ID3v2::Tag* tag2, const char* frameID, const char* value) {
133         int ret = METADATA_EDITOR_ERROR_NONE;
134
135         ret = __check_metadata_set_parameter(_metadata);
136         metadata_editor_retvm_if(ret != METADATA_EDITOR_ERROR_NONE, ret, "fail to __check_metadata_set_parameter() [%d]", ret);
137         metadata_editor_retvm_if(!frameID, METADATA_EDITOR_ERROR_INVALID_PARAMETER, "Invalid frameID");
138         metadata_editor_retvm_if(!tag2, METADATA_EDITOR_ERROR_OPERATION_FAILED, "Error. ID3v2 tag was not created. Can not proceed metadata updating");
139
140         // If the pointer is NULL or c-string is empty - handle as request for deletion
141         if (!value || (*value == '\0')) {
142                 metadata_editor_info("Request for frame %s deletion", frameID);
143                 tag2->removeFrames(frameID);
144                 if (tag1 && !tag1->isEmpty()) {
145                         if (!strcmp(frameID, "TPE1"))
146                                 tag1->setArtist("");
147                         else if (!strcmp(frameID, "TALB"))
148                                 tag1->setAlbum("");
149                         else if (!strcmp(frameID, "TCON"))
150                                 tag1->setGenre("");
151                         else if (!strcmp(frameID, "TIT2"))
152                                 tag1->setTitle("");
153                         else if (!strcmp(frameID, "TRCK"))
154                                 tag1->setTrack(0);
155                         else if (!strcmp(frameID, "TDRC"))
156                                 tag1->setYear(0);
157                 }
158
159                 return METADATA_EDITOR_ERROR_NONE;
160         }
161
162         // Check if the frame is empty (must create the frame before writing the data)
163         if (tag2->frameListMap()[frameID].isEmpty()) {
164                 metadata_editor_info("The frame %s does not exist. Creating", frameID);
165                 // This is a common frame type for textural frames except comment frame
166                 auto fr = new TagLib::ID3v2::TextIdentificationFrame(frameID);
167
168                 fr->setTextEncoding(TagLib::String::UTF8);
169                 fr->setText(TagLib::String(value, TagLib::String::UTF8));
170                 tag2->addFrame(fr);
171         } else {                // if not - just modify the data in the existing frame
172                 metadata_editor_info("The frame %s exists. Changing", frameID);
173                 tag2->frameListMap()[frameID][0]->setText(TagLib::String(value, TagLib::String::UTF8));
174         }
175
176         if (tag1 && !tag1->isEmpty()) {                         // Check if ID3v1 tag exists. Must copy data if yes.
177                 metadata_editor_info("ID3v1 tag also exists. Copying frame");
178                 if (!strcmp(frameID, "TPE1"))
179                                 tag1->setArtist(value);
180                 else if (!strcmp(frameID, "TALB"))
181                                 tag1->setAlbum(value);
182                 else if (!strcmp(frameID, "TCON"))              // Genre in ID3v1 is enumeration, so can not write it with "value"
183                                 tag1->setGenre("");
184                 else if (!strcmp(frameID, "TIT2"))
185                                 tag1->setTitle(value);
186                 else if (!strcmp(frameID, "TRCK"))
187                                 tag1->setTrack(atoi(value));
188                 else if (!strcmp(frameID, "TDRC"))
189                                 tag1->setYear(atoi(value));
190         }
191
192         return METADATA_EDITOR_ERROR_NONE;
193 }
194
195 static int __ID3_getFrameByName(metadata_editor_s *_metadata, TagLib::ID3v2::Tag *tag2, const char *frameID, char **value)
196 {
197         int ret = METADATA_EDITOR_ERROR_NONE;
198
199         ret = __check_metadata_get_parameter(_metadata, value);
200         metadata_editor_retvm_if(ret != METADATA_EDITOR_ERROR_NONE, ret, "fail to __check_metadata_get_parameter() [%d]", ret);
201         metadata_editor_retvm_if(!frameID, METADATA_EDITOR_ERROR_INVALID_PARAMETER, "Invalid frameID");
202         metadata_editor_retvm_if(!tag2 || tag2->frameListMap()[frameID].isEmpty(), METADATA_EDITOR_ERROR_NONE, "The frame %s does not exist", frameID);
203
204         metadata_editor_info("The frame %s exists", frameID);
205
206         *value = g_strdup(tag2->frameListMap()[frameID][0]->toString().toCString(true));
207
208         return METADATA_EDITOR_ERROR_NONE;
209 }
210
211 // *** This function writes frames that exist only in ID3v2 tag *** //
212 static int __ID3_setFrameByName(metadata_editor_s* _metadata, TagLib::ID3v2::Tag* tag2, const char* frameID, const char* value) {
213         int ret = METADATA_EDITOR_ERROR_NONE;
214
215         ret = __check_metadata_set_parameter(_metadata);
216         metadata_editor_retvm_if(ret != METADATA_EDITOR_ERROR_NONE, ret, "fail to __check_metadata_set_parameter() [%d]", ret);
217         metadata_editor_retvm_if(!frameID, METADATA_EDITOR_ERROR_INVALID_PARAMETER, "Invalid frameID");
218         metadata_editor_retvm_if(!tag2, METADATA_EDITOR_ERROR_OPERATION_FAILED, "Error. ID3v2 tag was not created. Can not proceed metadata updating");
219
220         // If the pointer is NULL or c-string is empty - handle as request for deletion
221         if (!value || (*value == '\0')) {
222                 metadata_editor_info("Request for frame %s deletion", frameID);
223                 tag2->removeFrames(frameID);
224                 return METADATA_EDITOR_ERROR_NONE;
225         }
226
227         // Check if the ID3v2 tag exists
228         if (tag2->frameListMap()[frameID].isEmpty()) {
229                 metadata_editor_info("The frame %s does not exist. Creating", frameID);
230                 // This is a common frame type for textural frames except comment frame
231                 auto fr = new TagLib::ID3v2::TextIdentificationFrame(frameID);
232
233                 fr->setTextEncoding(TagLib::String::UTF8);
234                 fr->setText(TagLib::String(value, TagLib::String::UTF8));
235                 tag2->addFrame(fr);
236         } else {                // if not - just modify the data in the existing frame
237                 metadata_editor_info("The frame %s exists. Changing", frameID);
238                 tag2->frameListMap()[frameID][0]->setText(TagLib::String(value, TagLib::String::UTF8));
239         }
240
241         return METADATA_EDITOR_ERROR_NONE;
242 }
243
244 static int __ID3_getNumberOfPictures(metadata_editor_s* _metadata, TagLib::ID3v2::Tag* tag2, char** value)
245 {
246         int ret = METADATA_EDITOR_ERROR_NONE;
247
248         ret = __check_metadata_get_parameter(_metadata, value);
249         metadata_editor_retvm_if(ret != METADATA_EDITOR_ERROR_NONE, ret, "fail to __check_metadata_get_parameter() [%d]", ret);
250         metadata_editor_retvm_if(!tag2, METADATA_EDITOR_ERROR_OPERATION_FAILED, "Error. ID3v2 tag does not exist. Can not process further");
251
252         *value = g_strdup_printf("%u", tag2->frameListMap()["APIC"].size());
253
254         return METADATA_EDITOR_ERROR_NONE;
255 }
256
257 static int __ID3_getLyricsFrame(metadata_editor_s *_metadata, TagLib::ID3v2::Tag *tag2, char **value)
258 {
259         int ret = METADATA_EDITOR_ERROR_NONE;
260
261         ret = __check_metadata_get_parameter(_metadata, value);
262         metadata_editor_retvm_if(ret != METADATA_EDITOR_ERROR_NONE, ret, "fail to __check_metadata_get_parameter() [%d]", ret);
263         metadata_editor_retvm_if(!tag2, METADATA_EDITOR_ERROR_OPERATION_FAILED, "Error. ID3v2 tag does not exist. Can not process further");
264
265         TagLib::ID3v2::FrameList lst = tag2->frameListMap()["USLT"];
266         metadata_editor_retvm_if(lst.isEmpty(), METADATA_EDITOR_ERROR_NONE, "The frame USLT does not exist");
267
268         metadata_editor_info("The frame USLT exists");
269         TagLib::ID3v2::FrameList::Iterator it = lst.begin();
270         auto frame = static_cast<TagLib::ID3v2::UnsynchronizedLyricsFrame*>(*it);
271
272         *value = g_strdup(frame->text().toCString(true));
273
274         return METADATA_EDITOR_ERROR_NONE;
275 }
276
277 // *** This function is used to set text in comment frame. It processes both ID3v1 and ID3v2 tags *** //
278 // *** Comment frame is different from other string-type frames. It uses CommentsFrame instead of TextIdentificationFrame *** //
279 static int __ID3_setTwixCommentFrame(metadata_editor_s* _metadata, TagLib::ID3v1::Tag* tag1, TagLib::ID3v2::Tag* tag2, const char* value) {
280         int ret = METADATA_EDITOR_ERROR_NONE;
281
282         ret = __check_metadata_set_parameter(_metadata);
283         metadata_editor_retvm_if(ret != METADATA_EDITOR_ERROR_NONE, ret, "fail to __check_metadata_set_parameter() [%d]", ret);
284         metadata_editor_retvm_if(!tag2, METADATA_EDITOR_ERROR_OPERATION_FAILED, "Error. ID3v2 tag was not created. Can not proceed metadata updating");
285
286         // If the pointer is NULL or c-string is empty - handle as request for deletion
287         if (!value || (*value == '\0')) {
288                 metadata_editor_info("Request for frame COMM deletion");
289                 tag2->removeFrames("COMM");
290                 if (tag1 && !tag1->isEmpty())
291                         tag1->setComment("");
292                 return METADATA_EDITOR_ERROR_NONE;
293         }
294         // If the comment frame is empty - create the frame and add it to the list
295         if (tag2->frameListMap()["COMM"].isEmpty()) {
296                 metadata_editor_info("The frame COMM does not exist. Creating");
297                 auto fr = new TagLib::ID3v2::CommentsFrame;
298
299                 fr->setText(TagLib::String(value, TagLib::String::UTF8));
300                 fr->setTextEncoding(TagLib::String::UTF8);
301                 tag2->addFrame(fr);
302         } else {                                                // If the frame already exists - just modify its value
303                 metadata_editor_info("The frame COMM exists. Changing");
304                 tag2->frameListMap()["COMM"][0]->setText(TagLib::String(value, TagLib::String::UTF8));
305         }
306
307         if (tag1 && !tag1->isEmpty()) {                 // Copy the value to ID3v1 tag comment
308                 metadata_editor_info("ID3v1 tag also exists. Copying frame");
309                 tag1->setComment(value);
310         }
311
312         return METADATA_EDITOR_ERROR_NONE;
313 }
314
315 // *** This function is used to set text in Lyrics frame *** //
316 // *** Lyrics frame is different from other string-type frames and uses UnsynchronizedLyricsFrame instead of TextIdentificationFrame *** //
317 static int __ID3_setLyricsFrame(metadata_editor_s* _metadata, TagLib::ID3v2::Tag* tag2, const char* value) {
318         int ret = METADATA_EDITOR_ERROR_NONE;
319
320         ret = __check_metadata_set_parameter(_metadata);
321         metadata_editor_retvm_if(ret != METADATA_EDITOR_ERROR_NONE, ret, "fail to __check_metadata_set_parameter() [%d]", ret);
322         metadata_editor_retvm_if(!tag2, METADATA_EDITOR_ERROR_OPERATION_FAILED, "Error. ID3v2 tag was not created. Can not proceed metadata updating");
323
324         TagLib::ID3v2::FrameList lst = tag2->frameListMap()["USLT"];    // link to unsynchronized lyric frames in tag
325         // If the pointer is NULL or c-string is empty - handle as request for deletion
326         if (!value || (*value == '\0')) {
327                 metadata_editor_info("Request for frame USLT deletion");
328                 tag2->removeFrames("USLT");
329                 return METADATA_EDITOR_ERROR_NONE;
330         }
331         // Check if lyrics frames exist
332         if (lst.isEmpty()) {
333                 // No lyrics - create the frame and add it to the ID3v2 tag
334                 metadata_editor_info("The frame USLT does not exist. Creating");
335                 auto frame = new TagLib::ID3v2::UnsynchronizedLyricsFrame;
336
337                 frame->setTextEncoding(TagLib::String::UTF8);
338                 frame->setText(TagLib::String(value, TagLib::String::UTF8));
339                 tag2->addFrame(frame);
340         } else {                                                                        // the lyrics frames exist - change the existing one
341                 metadata_editor_info("USLT frames exist in file. Changing");
342                 TagLib::ID3v2::FrameList::Iterator it = lst.begin();
343                 auto frame = static_cast<TagLib::ID3v2::UnsynchronizedLyricsFrame*>(*it);
344                 frame->setTextEncoding(TagLib::String::UTF8);
345                 frame->setText(TagLib::String(value, TagLib::String::UTF8));
346         }
347
348         return METADATA_EDITOR_ERROR_NONE;
349 }
350
351 static int __MP4_getStringItem(metadata_editor_s *_metadata, const char *itemname, char **value)
352 {
353         int ret = METADATA_EDITOR_ERROR_NONE;
354
355         ret = __check_metadata_get_parameter(_metadata, value);
356         metadata_editor_retvm_if(ret != METADATA_EDITOR_ERROR_NONE, ret, "fail to __check_metadata_get_parameter() [%d]", ret);
357         metadata_editor_retvm_if(!itemname, METADATA_EDITOR_ERROR_INVALID_PARAMETER, "Invalid  itemname");
358
359         auto tag = dynamic_cast<TagLib::MP4::Tag*>(_metadata->file->tag());
360         metadata_editor_retvm_if(!tag, METADATA_EDITOR_ERROR_OPERATION_FAILED, "Tag does not exist");
361
362         TagLib::MP4::ItemListMap& itemMap = tag->itemListMap();
363         TagLib::MP4::ItemListMap::ConstIterator it = itemMap.find(itemname);
364
365         if (it != itemMap.end())
366                 *value = g_strdup(it->second.toStringList()[0].toCString(true));
367         else
368                 metadata_editor_info("No item <%s> in file", itemname);
369
370         return METADATA_EDITOR_ERROR_NONE;
371 }
372
373 static int __MP4_getIntegerItem(metadata_editor_s *_metadata, const char *itemname, char **value)
374 {
375         int ret = METADATA_EDITOR_ERROR_NONE;
376
377         ret = __check_metadata_get_parameter(_metadata, value);
378         metadata_editor_retvm_if(ret != METADATA_EDITOR_ERROR_NONE, ret, "fail to __check_metadata_get_parameter() [%d]", ret);
379         metadata_editor_retvm_if(!itemname, METADATA_EDITOR_ERROR_INVALID_PARAMETER, "Invalid itemname");
380
381         auto tag = dynamic_cast<TagLib::MP4::Tag*>(_metadata->file->tag());
382         metadata_editor_retvm_if(!tag, METADATA_EDITOR_ERROR_OPERATION_FAILED, "Tag does not exist");
383
384         TagLib::MP4::ItemListMap& itemMap = tag->itemListMap();
385         TagLib::MP4::ItemListMap::ConstIterator it = itemMap.find(itemname);
386
387         if (it != itemMap.end())
388                 *value = g_strdup_printf("%u", it->second.toInt());
389         else
390                 metadata_editor_info("No item <%s> in file", itemname);
391
392         return METADATA_EDITOR_ERROR_NONE;
393 }
394
395 static int __MP4_updateStringItem(metadata_editor_s* _metadata, const char* itemname, const char* value)
396 {
397         int ret = METADATA_EDITOR_ERROR_NONE;
398
399         ret = __check_metadata_set_parameter(_metadata);
400         metadata_editor_retvm_if(ret != METADATA_EDITOR_ERROR_NONE, ret, "fail to __check_metadata_set_parameter() [%d]", ret);
401         metadata_editor_retvm_if(!itemname, METADATA_EDITOR_ERROR_INVALID_PARAMETER, "Invalid itemname");
402
403         auto tag = dynamic_cast<TagLib::MP4::Tag*>(_metadata->file->tag());
404         metadata_editor_retvm_if(!tag, METADATA_EDITOR_ERROR_OPERATION_FAILED, "Tag does not exist");
405
406         // Get map of items directly from tag and launch a search of specific item
407         TagLib::MP4::ItemListMap& itemMap = tag->itemListMap();
408         // Check if it is a request for deletion
409         if ((value == NULL) || value[0] == '\0') {
410                 metadata_editor_info("Request for deleting of item <%s>", itemname);
411                 TagLib::MP4::ItemListMap::Iterator it = itemMap.find(itemname);
412                 if (it != itemMap.end())
413                         itemMap.erase(it);
414                 return METADATA_EDITOR_ERROR_NONE;
415         }
416         metadata_editor_info("The item <%s> will be added", itemname);
417         itemMap[itemname] = TagLib::MP4::Item(TagLib::String(value, TagLib::String::UTF8));
418
419         return METADATA_EDITOR_ERROR_NONE;
420 }
421
422 static int __MP4_updateIntegerItem(metadata_editor_s* _metadata, const char* itemname, const char* value)
423 {
424         int ret = METADATA_EDITOR_ERROR_NONE;
425
426         ret = __check_metadata_set_parameter(_metadata);
427         metadata_editor_retvm_if(ret != METADATA_EDITOR_ERROR_NONE, ret, "fail to __check_metadata_set_parameter() [%d]", ret);
428         metadata_editor_retvm_if(!itemname, METADATA_EDITOR_ERROR_INVALID_PARAMETER, "Invalid itemname");
429
430         auto tag = dynamic_cast<TagLib::MP4::Tag*>(_metadata->file->tag());
431         metadata_editor_retvm_if(!tag, METADATA_EDITOR_ERROR_OPERATION_FAILED, "Tag does not exist");
432
433         // Get map of items directly from tag and launch a search of specific item
434         TagLib::MP4::ItemListMap& itemMap = tag->itemListMap();
435         // Check if it is a request for deletion
436         if ((value == NULL) || value[0] == '\0') {
437                 metadata_editor_info("Request for deleting of item <%s>", itemname);
438                 TagLib::MP4::ItemListMap::Iterator it = itemMap.find(itemname);
439                 if (it != itemMap.end())
440                         itemMap.erase(it);
441                 return METADATA_EDITOR_ERROR_NONE;
442         }
443         // Check if the value is integer string then it can be successfully converted into integer
444         if (isdigit(value[0])) {
445                 metadata_editor_info("The item <%s> will be added", itemname);
446                 int number = atoi(value);
447                 itemMap[itemname] = TagLib::MP4::Item(number);
448                 return METADATA_EDITOR_ERROR_NONE;
449         } else {                                                                                // Notify that string is not a number to process
450                 metadata_editor_error("Error. String does not contain a number");
451                 return METADATA_EDITOR_ERROR_INVALID_PARAMETER;
452         }
453 }
454
455 static int __MP4_getNumberOfPictures(metadata_editor_s* _metadata, char** value)
456 {
457         int ret = METADATA_EDITOR_ERROR_NONE;
458
459         ret = __check_metadata_get_parameter(_metadata, value);
460         metadata_editor_retvm_if(ret != METADATA_EDITOR_ERROR_NONE, ret, "fail to __check_metadata_get_parameter() [%d]", ret);
461
462         auto tag = dynamic_cast<TagLib::MP4::Tag*>(_metadata->file->tag());
463         metadata_editor_retvm_if(!tag, METADATA_EDITOR_ERROR_OPERATION_FAILED, "Tag does not exist");
464
465         *value = g_strdup_printf("%u", tag->contains("covr") ? tag->item("covr").toCoverArtList().size() : 0);
466
467         return METADATA_EDITOR_ERROR_NONE;
468 }
469
470 #if 0
471 static int __xiph_getFieldValue(metadata_editor_s *_metadata, TagLib::Ogg::XiphComment *xtag, const char *fieldname, char **value)
472 {
473         int ret = METADATA_EDITOR_ERROR_NONE;
474
475         ret = __check_metadata_get_parameter(_metadata, value);
476         metadata_editor_retvm_if(ret != METADATA_EDITOR_ERROR_NONE, ret, "fail to __check_metadata_get_parameter() [%d]", ret);
477         metadata_editor_retvm_if(!fieldname, METADATA_EDITOR_ERROR_INVALID_PARAMETER, "Invalid fieldname");
478         metadata_editor_retvm_if(!xtag, METADATA_EDITOR_ERROR_OPERATION_FAILED, "Tag does not exist");
479
480         const TagLib::Ogg::FieldListMap& fieldMap = xtag->fieldListMap();
481         TagLib::Ogg::FieldListMap::ConstIterator it = fieldMap.find(fieldname);
482
483         if ((xtag->contains(fieldname)) && (it != fieldMap.end()))
484                 *value = g_strdup(it->second[0].toCString(true));
485         else
486                 metadata_editor_info("No field %s in Xiph Comment", fieldname);
487
488         return METADATA_EDITOR_ERROR_NONE;
489 }
490
491 // *** This function is used to write string into Xiph Comment fields *** //
492 static int __xiph_updateFieldValue(metadata_editor_s* _metadata, TagLib::Ogg::XiphComment* xtag, const char* fieldname, const char* value) {
493         int ret = METADATA_EDITOR_ERROR_NONE;
494
495         ret = __check_metadata_set_parameter(_metadata);
496         metadata_editor_retvm_if(ret != METADATA_EDITOR_ERROR_NONE, ret, "fail to __check_metadata_set_parameter() [%d]", ret);
497         metadata_editor_retvm_if(!fieldname, METADATA_EDITOR_ERROR_INVALID_PARAMETER, "Invalid fieldname");
498         metadata_editor_retvm_if(!xtag, METADATA_EDITOR_ERROR_OPERATION_FAILED, "Tag does not exist");
499
500         // Check if it is a request for deletion
501         if ((value == NULL) || value[0] == '\0') {
502                 metadata_editor_info("Request for deleting of field %s", fieldname);
503                 xtag->removeField(fieldname);
504                 return METADATA_EDITOR_ERROR_NONE;
505         }
506         metadata_editor_info("The field %s will be added", fieldname);
507         // "true" is used to remove other strings of the same "fieldname" first
508         xtag->addField(fieldname, TagLib::String(value, TagLib::String::UTF8), true);
509         return METADATA_EDITOR_ERROR_NONE;
510 }
511
512 static int __FLAC_getNumberOfPictures(metadata_editor_s* _metadata, char** value)
513 {
514         int ret = METADATA_EDITOR_ERROR_NONE;
515
516         ret = __check_metadata_get_parameter(_metadata, value);
517         metadata_editor_retvm_if(ret != METADATA_EDITOR_ERROR_NONE, ret, "fail to __check_metadata_get_parameter() [%d]", ret);
518
519         TagLib::FLAC::File* _file = (TagLib::FLAC::File*) _metadata->file;
520
521         *value = g_strdup_printf("%u", _file->pictureList().size());
522
523         return METADATA_EDITOR_ERROR_NONE;
524 }
525 #endif
526 int __metadata_editor_get_file_ext(const char *file_path, char *file_ext, int max_len) {
527         int i = 0;
528         unsigned int path_len = strlen(file_path);
529
530         for (i = (int)path_len; i >= 0; i--) {
531                 if ((file_path[i] == '.') && (i < (int)path_len)) {
532                         strncpy(file_ext, &file_path[i + 1], max_len);
533                         return 0;
534                 }
535
536                 /* meet the dir. no ext */
537                 if (file_path[i] == '/')
538                         return -1;
539         }
540
541         return -1;
542 }
543
544 int __metadata_editor_get_file_type(const char *path) {
545         int ret = 0;
546         char mimetype[255] = {0, };
547
548         /* get content type and mime type from file. */
549         ret = aul_get_mime_from_file(path, mimetype, sizeof(mimetype));
550         if (ret < 0) {
551                 metadata_editor_debug("aul_get_mime_from_file fail.. Now trying to get type by extension");
552
553                 char ext[255] = { 0 };
554                 int ret = __metadata_editor_get_file_ext(path, ext, sizeof(ext));
555                 metadata_editor_retvm_if(ret < 0, METADATA_EDITOR_FORMAT_NOTYPE, "__metadata_editor_get_file_ext failed");
556
557                 if (strcasecmp(ext, "MP3") == 0)
558                         return METADATA_EDITOR_FORMAT_MP3;
559                 else if (strcasecmp(ext, "MP4") == 0)
560                         return METADATA_EDITOR_FORMAT_MP4;
561                 else
562                         return METADATA_EDITOR_FORMAT_NOTYPE;
563         }
564
565         metadata_editor_debug("mime type : %s", mimetype);
566
567         /* categorize from mimetype */
568         if (strstr(mimetype, "mpeg") != NULL)
569                 return METADATA_EDITOR_FORMAT_MP3;
570         else if (strstr(mimetype, "mp4") != NULL)
571                 return METADATA_EDITOR_FORMAT_MP4;
572
573         return METADATA_EDITOR_FORMAT_NOTYPE;
574 }
575
576 static int __metadata_editor_get_picture_type(const char *path, char **type) {
577         int ret = 0;
578         char mimetype[255] = {0, };
579
580         /* get content type and mime type from file. */
581         ret = aul_get_mime_from_file(path, mimetype, sizeof(mimetype));
582         if (ret < 0) {
583                 metadata_editor_debug("aul_get_mime_from_file fail.. Now trying to get type by extension");
584
585                 char ext[255] = { 0 };
586                 int ret = __metadata_editor_get_file_ext(path, ext, sizeof(ext));
587                 metadata_editor_retvm_if(ret < 0, METADATA_EDITOR_ERROR_OPERATION_FAILED, "__metadata_editor_get_file_ext failed");
588
589                 if (strcasecmp(ext, "JPG") == 0 || strcasecmp(ext, "JPEG") == 0) {
590                         *type = g_strdup(MIME_TYPE_JPEG);
591                         return METADATA_EDITOR_ERROR_NONE;
592                 } else if (strcasecmp(ext, "PNG") == 0) {
593                         *type = g_strdup(MIME_TYPE_JPEG);
594                         return METADATA_EDITOR_ERROR_NONE;
595                 } else {
596                         return METADATA_EDITOR_ERROR_NOT_SUPPORTED;
597                 }
598         }
599
600         metadata_editor_debug("mime type : %s", mimetype);
601
602         /* categorize from mimetype */
603         if (strstr(mimetype, "jpeg") != NULL) {
604                 *type = g_strndup(mimetype, strlen(mimetype));
605                 return METADATA_EDITOR_ERROR_NONE;
606         } else if (strstr(mimetype, "png") != NULL) {
607                 *type = g_strndup(mimetype, strlen(mimetype));
608                 return METADATA_EDITOR_ERROR_NONE;
609         }
610
611         return METADATA_EDITOR_ERROR_NOT_SUPPORTED;
612 }
613
614 int __metadata_editor_get_picture_info(const char *path, void **picture, size_t *size, char **type) {
615         int ret;
616
617         ret = __metadata_editor_get_picture_type(path, type);
618         if (ret != METADATA_EDITOR_ERROR_NONE)
619                 return METADATA_EDITOR_ERROR_OPERATION_FAILED;
620
621         //IF ok.. read file
622         FILE* fin = fopen(path, "rb");
623         size_t file_size = 0;
624
625         if (fin) {
626                 while (fgetc(fin) != EOF)
627                         file_size++;
628
629                 fclose(fin);
630                 char picture_buffer[file_size] = {0, };
631                 memset(picture_buffer, 0, file_size * sizeof(char));
632                 fin = fopen(path, "rb");
633                 if (fin) {
634                         if(file_size != fread(picture_buffer, 1, file_size, fin)) {
635                                 metadata_editor_error("fread error");
636                                 fclose(fin);
637                                 return METADATA_EDITOR_ERROR_OPERATION_FAILED;
638                         }
639                         fclose(fin);
640                 }
641                 if (*picture == NULL) {
642                         *picture = malloc(file_size * sizeof(char));
643                         memset(*picture, 0, file_size * sizeof(char));
644                         memcpy(*picture, picture_buffer, file_size);
645                         *size = file_size;
646                 }
647         }
648
649         return METADATA_EDITOR_ERROR_NONE;
650 }
651
652 // *** This function is used to allocate the metadata_editor_s in memory                *** //
653 // *** The structure metadata_editor_s contains all information about the file  *** //
654 extern "C" int metadata_editor_create(metadata_editor_h *metadata) {
655         metadata_editor_retvm_if(metadata == NULL, METADATA_EDITOR_ERROR_INVALID_PARAMETER, "Invalid metadata");
656
657         metadata_editor_s *_metadata = g_new0(metadata_editor_s, 1);
658
659         _metadata->file = NULL;
660         _metadata->filetype = METADATA_EDITOR_FORMAT_NOTYPE;                    // Specify file type out of range
661
662         // Save the structure in the metadata
663         *metadata = (metadata_editor_h)_metadata;
664
665         return METADATA_EDITOR_ERROR_NONE;
666 }
667
668 // *** This function is used to open the file. It creates the instance that is responsible for connection with file *** //
669 extern "C" int metadata_editor_set_path(metadata_editor_h metadata, const char *path) {
670         int media_type = METADATA_EDITOR_FORMAT_NOTYPE;
671         metadata_editor_s *_metadata = (metadata_editor_s*)metadata;
672         TagLib::File* _file = NULL;
673
674         metadata_editor_retvm_if(!_metadata, METADATA_EDITOR_ERROR_INVALID_PARAMETER, "Invalid metadata");
675         metadata_editor_retvm_if(!path, METADATA_EDITOR_ERROR_INVALID_PARAMETER, "Invalid path");
676
677         if (access(path, R_OK) < 0) {
678                 if (errno == EACCES || errno == EPERM) {
679                         metadata_editor_error("Permission denied");
680                         return METADATA_EDITOR_ERROR_PERMISSION_DENIED;
681                 } else {
682                         metadata_editor_error("Fail to open path");
683                         return METADATA_EDITOR_ERROR_FILE_EXISTS;
684                 }
685         }
686
687         media_type = __metadata_editor_get_file_type(path);
688
689         if (_metadata->file) {
690                 metadata_editor_info("file free [%p]", _metadata->file);
691                 delete _metadata->file;
692
693                 _metadata->file = NULL;
694                 _metadata->filetype = METADATA_EDITOR_FORMAT_NOTYPE;
695         }
696
697         try {
698         switch (media_type) {
699         case METADATA_EDITOR_FORMAT_MP3:
700                 _file = new TagLib::MPEG::File(path);
701                 break;
702
703         case METADATA_EDITOR_FORMAT_MP4:
704                 _file = new TagLib::MP4::File(path);
705                 break;
706
707 #if 0
708         case METADATA_EDITOR_FORMAT_FLAC:
709                 _file = new TagLib::FLAC::File(path);
710                 break;
711
712         case METADATA_EDITOR_FORMAT_OGG_VORBIS:
713                 _file = new TagLib::Ogg::Vorbis::File(path);
714                 break;
715
716         case METADATA_EDITOR_FORMAT_OGG_FLAC:
717                 _file = new TagLib::Ogg::FLAC::File(path);
718                 break;
719
720         case METADATA_EDITOR_FORMAT_WAV:
721                 // Allocate the file object in memory to work with it later on
722                 _file = new TagLib::RIFF::WAV::File(path);
723                 break;
724
725 #endif
726         default:
727                 metadata_editor_error("Wrong file type");
728                 return METADATA_EDITOR_ERROR_NOT_SUPPORTED;
729         }
730         } catch (const std::bad_alloc &ex) {
731                 metadata_editor_retvm_if(!_file, METADATA_EDITOR_ERROR_OUT_OF_MEMORY, "OUT_OF_MEMORY");
732         }
733
734         if (!_file->isOpen()) {
735                 metadata_editor_error("The file was not found. Pointer address is %p", _file);
736                 delete _file;
737                 return METADATA_EDITOR_ERROR_PERMISSION_DENIED;
738         }
739
740         _metadata->file = _file;
741         _metadata->filetype = media_type;
742
743         return METADATA_EDITOR_ERROR_NONE;
744 }
745
746 static int __metadata_editor_get_mp3_metadata(metadata_editor_s *metadata, metadata_editor_attr_e attribute, char **value)
747 {
748         int ret = METADATA_EDITOR_ERROR_NONE;
749
750         ret = __check_metadata_get_parameter(metadata, value);
751         metadata_editor_retvm_if(ret != METADATA_EDITOR_ERROR_NONE, ret, "fail to __check_metadata_get_parameter() [%d]", ret);
752
753         // Bring the pointer to actual file type and make tag pointers
754         TagLib::MPEG::File* _file = (TagLib::MPEG::File*)metadata->file;
755         TagLib::ID3v1::Tag* tag1 = _file->ID3v1Tag();
756         TagLib::ID3v2::Tag* tag2 = _file->ID3v2Tag();
757
758         switch (attribute) {                                    // Check which one of frame types was given to the function for processing
759                 case METADATA_EDITOR_ATTR_ARTIST:                       return __ID3_getTwixFrameByName(metadata, tag1, tag2, "TPE1", value);
760                 case METADATA_EDITOR_ATTR_TITLE:                        return __ID3_getTwixFrameByName(metadata, tag1, tag2, "TIT2", value);
761                 case METADATA_EDITOR_ATTR_ALBUM:                        return __ID3_getTwixFrameByName(metadata, tag1, tag2, "TALB", value);
762                 case METADATA_EDITOR_ATTR_GENRE:                        return __ID3_getTwixFrameByName(metadata, tag1, tag2, "TCON", value);
763                 case METADATA_EDITOR_ATTR_AUTHOR:                       return __ID3_getFrameByName(metadata, tag2, "TCOM", value);
764                 case METADATA_EDITOR_ATTR_COPYRIGHT:                    return __ID3_getFrameByName(metadata, tag2, "TCOP", value);
765                 case METADATA_EDITOR_ATTR_DATE:                 return __ID3_getTwixFrameByName(metadata, tag1, tag2, "TDRC", value);
766                 case METADATA_EDITOR_ATTR_DESCRIPTION:          return __ID3_getFrameByName(metadata, tag2, "TIT3", value);
767                 case METADATA_EDITOR_ATTR_COMMENT:                      return __ID3_getTwixFrameByName(metadata, tag1, tag2, "COMM", value);
768                 case METADATA_EDITOR_ATTR_TRACK_NUM:                    return __ID3_getTwixFrameByName(metadata, tag1, tag2, "TRCK", value);
769                 case METADATA_EDITOR_ATTR_CONDUCTOR:                    return __ID3_getFrameByName(metadata, tag2, "TPE3", value);
770                 case METADATA_EDITOR_ATTR_PICTURE_NUM:                  return __ID3_getNumberOfPictures(metadata, tag2, value);
771                 case METADATA_EDITOR_ATTR_UNSYNCLYRICS:                 return __ID3_getLyricsFrame(metadata, tag2, value);
772                 default:
773                         return METADATA_EDITOR_ERROR_INVALID_PARAMETER;
774         }
775 }
776
777 static int __metadata_editor_get_mp4_metadata(metadata_editor_s *metadata, metadata_editor_attr_e attribute, char **value)
778 {
779         int ret = METADATA_EDITOR_ERROR_NONE;
780
781         ret = __check_metadata_get_parameter(metadata, value);
782         metadata_editor_retvm_if(ret != METADATA_EDITOR_ERROR_NONE, ret, "fail to __check_metadata_get_parameter() [%d]", ret);
783
784         switch (attribute) {                                    // Check which one of frame types was given to the function for processing
785         case METADATA_EDITOR_ATTR_ARTIST:                       return __MP4_getStringItem(metadata, "\xA9""ART", value);
786         case METADATA_EDITOR_ATTR_TITLE:                        return __MP4_getStringItem(metadata, "\xA9""nam", value);
787         case METADATA_EDITOR_ATTR_ALBUM:                        return __MP4_getStringItem(metadata, "\xA9""alb", value);
788         case METADATA_EDITOR_ATTR_GENRE:                        return __MP4_getStringItem(metadata, "\xA9""gen", value);
789         case METADATA_EDITOR_ATTR_AUTHOR:                       return __MP4_getStringItem(metadata, "\xA9""wrt", value);
790         case METADATA_EDITOR_ATTR_COPYRIGHT:                    return __MP4_getStringItem(metadata, "cprt", value);
791         case METADATA_EDITOR_ATTR_DATE:                 return __MP4_getStringItem(metadata, "\xA9""day", value);
792         case METADATA_EDITOR_ATTR_DESCRIPTION:          return __MP4_getStringItem(metadata, "desc", value);
793         case METADATA_EDITOR_ATTR_COMMENT:                      return __MP4_getStringItem(metadata, "\xA9""cmt", value);
794         case METADATA_EDITOR_ATTR_TRACK_NUM:                    return __MP4_getIntegerItem(metadata, "trkn", value);
795         case METADATA_EDITOR_ATTR_CONDUCTOR:                    return __MP4_getStringItem(metadata, "cond", value);
796         case METADATA_EDITOR_ATTR_UNSYNCLYRICS:                 return __MP4_getStringItem(metadata, "\xA9""lyr", value);
797         case METADATA_EDITOR_ATTR_PICTURE_NUM:                  return __MP4_getNumberOfPictures(metadata, value);
798         default:
799                 return METADATA_EDITOR_ERROR_INVALID_PARAMETER;
800 }
801 }
802
803 #if 0
804 static int __metadata_editor_get_flac_metadata(metadata_editor_s *metadata, metadata_editor_attr_e attribute, char **value)
805 {
806         int ret = METADATA_EDITOR_ERROR_NONE;
807
808         ret = __check_metadata_get_parameter(metadata, value);
809         metadata_editor_retvm_if(ret != METADATA_EDITOR_ERROR_NONE, ret, "fail to __check_metadata_get_parameter() [%d]", ret);
810
811         // Bring the pointer to actual file type and make tags pointers
812         TagLib::FLAC::File* _file = (TagLib::FLAC::File*)metadata->file;
813         TagLib::Ogg::XiphComment* xtag = _file->xiphComment(false);
814         if (!xtag) {                                                                    // Check if we have a valid tag for processing
815                 metadata_editor_error("Tag does not exist");
816                 *value = NULL;
817                 return METADATA_EDITOR_ERROR_OPERATION_FAILED;
818         }
819         switch (attribute) {                                    // Check which one of frame types was given to the function for processing
820                 case METADATA_EDITOR_ATTR_ARTIST:                       return __xiph_getFieldValue(metadata, xtag, "ARTIST", value);
821                 case METADATA_EDITOR_ATTR_TITLE:                        return __xiph_getFieldValue(metadata, xtag, "TITLE", value);
822                 case METADATA_EDITOR_ATTR_ALBUM:                        return __xiph_getFieldValue(metadata, xtag, "ALBUM", value);
823                 case METADATA_EDITOR_ATTR_GENRE:                        return __xiph_getFieldValue(metadata, xtag, "GENRE", value);
824                 case METADATA_EDITOR_ATTR_AUTHOR:                       return __xiph_getFieldValue(metadata, xtag, "COMPOSER", value);
825                 case METADATA_EDITOR_ATTR_COPYRIGHT:                    return __xiph_getFieldValue(metadata, xtag, "COPYRIGHT", value);
826                 case METADATA_EDITOR_ATTR_DATE:                 return __xiph_getFieldValue(metadata, xtag, "DATE", value);
827                 case METADATA_EDITOR_ATTR_DESCRIPTION:          return __xiph_getFieldValue(metadata, xtag, "DESCRIPTION", value);
828                 case METADATA_EDITOR_ATTR_COMMENT:                      return __xiph_getFieldValue(metadata, xtag, "COMMENT", value);
829                 case METADATA_EDITOR_ATTR_TRACK_NUM:                    return __xiph_getFieldValue(metadata, xtag, "TRACKNUMBER", value);
830                 case METADATA_EDITOR_ATTR_CONDUCTOR:                    return __xiph_getFieldValue(metadata, xtag, "CONDUCTOR", value);
831                 case METADATA_EDITOR_ATTR_UNSYNCLYRICS:                 return __xiph_getFieldValue(metadata, xtag, "LYRICS", value);
832                 case METADATA_EDITOR_ATTR_PICTURE_NUM:                  return __FLAC_getNumberOfPictures(metadata, value);
833                 default:
834                         return METADATA_EDITOR_ERROR_INVALID_PARAMETER;
835         }
836 }
837
838 static int __metadata_editor_get_ogg_vorbis_metadata(metadata_editor_s *metadata, metadata_editor_attr_e attribute, char **value)
839 {
840         int ret = METADATA_EDITOR_ERROR_NONE;
841
842         ret = __check_metadata_get_parameter(metadata, value);
843         metadata_editor_retvm_if(ret != METADATA_EDITOR_ERROR_NONE, ret, "fail to __check_metadata_get_parameter() [%d]", ret);
844
845         // Bring the pointer to actual file type and make tags pointers
846         TagLib::Ogg::Vorbis::File* _file = (TagLib::Ogg::Vorbis::File*)metadata->file;
847         TagLib::Ogg::XiphComment* xtag = _file->tag();
848         if (!xtag) {                                                                    // Check if we have a valid tag for processing
849                 metadata_editor_error("Tag does not exist");
850                 *value = NULL;
851                 return METADATA_EDITOR_ERROR_OPERATION_FAILED;
852         }
853         switch (attribute) {                                    // Check which one of frame types was given to the function for processing
854                 case METADATA_EDITOR_ATTR_ARTIST:                       return __xiph_getFieldValue(metadata, xtag, "ARTIST", value);
855                 case METADATA_EDITOR_ATTR_TITLE:                        return __xiph_getFieldValue(metadata, xtag, "TITLE", value);
856                 case METADATA_EDITOR_ATTR_ALBUM:                        return __xiph_getFieldValue(metadata, xtag, "ALBUM", value);
857                 case METADATA_EDITOR_ATTR_GENRE:                        return __xiph_getFieldValue(metadata, xtag, "GENRE", value);
858                 case METADATA_EDITOR_ATTR_AUTHOR:                       return __xiph_getFieldValue(metadata, xtag, "COMPOSER", value);
859                 case METADATA_EDITOR_ATTR_COPYRIGHT:                    return __xiph_getFieldValue(metadata, xtag, "COPYRIGHT", value);
860                 case METADATA_EDITOR_ATTR_DATE:                 return __xiph_getFieldValue(metadata, xtag, "DATE", value);
861                 case METADATA_EDITOR_ATTR_DESCRIPTION:          return __xiph_getFieldValue(metadata, xtag, "DESCRIPTION", value);
862                 case METADATA_EDITOR_ATTR_COMMENT:                      return __xiph_getFieldValue(metadata, xtag, "COMMENT", value);
863                 case METADATA_EDITOR_ATTR_TRACK_NUM:                    return __xiph_getFieldValue(metadata, xtag, "TRACKNUMBER", value);
864                 case METADATA_EDITOR_ATTR_CONDUCTOR:                    return __xiph_getFieldValue(metadata, xtag, "CONDUCTOR", value);
865                 case METADATA_EDITOR_ATTR_UNSYNCLYRICS:                 return __xiph_getFieldValue(metadata, xtag, "LYRICS", value);
866                 default:
867                         return METADATA_EDITOR_ERROR_INVALID_PARAMETER;
868         }
869 }
870
871 static int __metadata_editor_get_ogg_flac_metadata(metadata_editor_s *metadata, metadata_editor_attr_e attribute, char **value)
872 {
873         int ret = METADATA_EDITOR_ERROR_NONE;
874
875         ret = __check_metadata_get_parameter(metadata, value);
876         metadata_editor_retvm_if(ret != METADATA_EDITOR_ERROR_NONE, ret, "fail to __check_metadata_get_parameter() [%d]", ret);
877
878         // Bring the pointer to actual file type and make tags pointers
879         TagLib::Ogg::FLAC::File* _file = (TagLib::Ogg::FLAC::File*)metadata->file;
880         TagLib::Ogg::XiphComment* xtag = _file->tag();
881         if (!xtag) {                                                                    // Check if we have a valid tag for processing
882                 metadata_editor_error("Tag does not exist");
883                 *value = NULL;
884                 return METADATA_EDITOR_ERROR_OPERATION_FAILED;
885         }
886         switch (attribute) {                                    // Check which one of frame types was given to the function for processing
887                 case METADATA_EDITOR_ATTR_ARTIST:                       return __xiph_getFieldValue(metadata, xtag, "ARTIST", value);
888                 case METADATA_EDITOR_ATTR_TITLE:                        return __xiph_getFieldValue(metadata, xtag, "TITLE", value);
889                 case METADATA_EDITOR_ATTR_ALBUM:                        return __xiph_getFieldValue(metadata, xtag, "ALBUM", value);
890                 case METADATA_EDITOR_ATTR_GENRE:                        return __xiph_getFieldValue(metadata, xtag, "GENRE", value);
891                 case METADATA_EDITOR_ATTR_AUTHOR:                       return __xiph_getFieldValue(metadata, xtag, "COMPOSER", value);
892                 case METADATA_EDITOR_ATTR_COPYRIGHT:                    return __xiph_getFieldValue(metadata, xtag, "COPYRIGHT", value);
893                 case METADATA_EDITOR_ATTR_DATE:                 return __xiph_getFieldValue(metadata, xtag, "DATE", value);
894                 case METADATA_EDITOR_ATTR_DESCRIPTION:          return __xiph_getFieldValue(metadata, xtag, "DESCRIPTION", value);
895                 case METADATA_EDITOR_ATTR_COMMENT:                      return __xiph_getFieldValue(metadata, xtag, "COMMENT", value);
896                 case METADATA_EDITOR_ATTR_TRACK_NUM:                    return __xiph_getFieldValue(metadata, xtag, "TRACKNUMBER", value);
897                 case METADATA_EDITOR_ATTR_CONDUCTOR:                    return __xiph_getFieldValue(metadata, xtag, "CONDUCTOR", value);
898                 case METADATA_EDITOR_ATTR_UNSYNCLYRICS:                 return __xiph_getFieldValue(metadata, xtag, "LYRICS", value);
899                 default:
900                         return METADATA_EDITOR_ERROR_INVALID_PARAMETER;
901         }
902 }
903
904 static int __metadata_editor_get_wav_metadata(metadata_editor_s *metadata, metadata_editor_attr_e attribute, char **value)
905 {
906         int ret = METADATA_EDITOR_ERROR_NONE;
907
908         ret = __check_metadata_get_parameter(metadata, value);
909         metadata_editor_retvm_if(ret != METADATA_EDITOR_ERROR_NONE, ret, "fail to __check_metadata_get_parameter() [%d]", ret);
910
911         // Bring the pointer to actual file type and make tag pointers
912         TagLib::RIFF::WAV::File* _file = (TagLib::RIFF::WAV::File*)metadata->file;
913         TagLib::ID3v2::Tag* tag2 = _file->tag();
914
915         if (tag2 == NULL) {                                                             // Check if we have a valid tag for processing
916                 metadata_editor_error("Error. ID3v2 tag does not exist. Can not proceed metadata extraction");
917                 *value = NULL;
918                 return METADATA_EDITOR_ERROR_OPERATION_FAILED;
919         }
920
921         switch (attribute) {                                    // Check which one of frame types was given to the function for processing
922                 case METADATA_EDITOR_ATTR_ARTIST:                       return __ID3_getFrameByName(metadata, tag2, "TPE1", value);
923                 case METADATA_EDITOR_ATTR_TITLE:                        return __ID3_getFrameByName(metadata, tag2, "TIT2", value);
924                 case METADATA_EDITOR_ATTR_ALBUM:                        return __ID3_getFrameByName(metadata, tag2, "TALB", value);
925                 case METADATA_EDITOR_ATTR_GENRE:                        return __ID3_getFrameByName(metadata, tag2, "TCON", value);
926                 case METADATA_EDITOR_ATTR_AUTHOR:                       return __ID3_getFrameByName(metadata, tag2, "TCOM", value);
927                 case METADATA_EDITOR_ATTR_COPYRIGHT:                    return __ID3_getFrameByName(metadata, tag2, "TCOP", value);
928                 case METADATA_EDITOR_ATTR_DATE:                 return __ID3_getFrameByName(metadata, tag2, "TDRC", value);
929                 case METADATA_EDITOR_ATTR_DESCRIPTION:          return __ID3_getFrameByName(metadata, tag2, "TIT3", value);
930                 case METADATA_EDITOR_ATTR_COMMENT:                      return __ID3_getFrameByName(metadata, tag2, "COMM", value);
931                 case METADATA_EDITOR_ATTR_TRACK_NUM:                    return __ID3_getFrameByName(metadata, tag2, "TRCK", value);
932                 case METADATA_EDITOR_ATTR_CONDUCTOR:                    return __ID3_getFrameByName(metadata, tag2, "TPE3", value);
933                 case METADATA_EDITOR_ATTR_PICTURE_NUM:                  return __ID3_getNumberOfPictures(metadata, tag2, value);
934                 case METADATA_EDITOR_ATTR_UNSYNCLYRICS:                 return __ID3_getLyricsFrame(metadata, tag2, value);
935                 default:
936                         return METADATA_EDITOR_ERROR_INVALID_PARAMETER;
937         }
938 }
939 #endif
940
941 // *** This function is used to get the tag frame (field, item - each tag has its own name for data unit) from file *** //
942 extern "C" int metadata_editor_get_metadata(metadata_editor_h metadata, metadata_editor_attr_e attribute, char **value) {
943
944         metadata_editor_s *_metadata = (metadata_editor_s*)metadata;
945         metadata_editor_retvm_if(!_metadata, METADATA_EDITOR_ERROR_INVALID_PARAMETER, "Invalid metadata");
946
947         switch (_metadata->filetype) {
948         case METADATA_EDITOR_FORMAT_MP3:
949                 return __metadata_editor_get_mp3_metadata(_metadata, attribute, value);
950
951         case METADATA_EDITOR_FORMAT_MP4:
952                 return __metadata_editor_get_mp4_metadata(_metadata, attribute, value);
953
954 #if 0
955         case METADATA_EDITOR_FORMAT_FLAC:
956                 return __metadata_editor_get_flac_metadata(_metadata, attribute, value);
957
958         case METADATA_EDITOR_FORMAT_OGG_VORBIS:
959                 return __metadata_editor_get_ogg_vorbis_metadata(_metadata, attribute, value);
960
961         case METADATA_EDITOR_FORMAT_OGG_FLAC:
962                 return __metadata_editor_get_ogg_flac_metadata(_metadata, attribute, value);
963
964         case METADATA_EDITOR_FORMAT_WAV:
965                 return __metadata_editor_get_wav_metadata(_metadata, attribute, value);
966
967 #endif
968         default:
969                 metadata_editor_error("Wrong file type [%d]", _metadata->filetype);
970                 return METADATA_EDITOR_ERROR_INVALID_PARAMETER;
971         }
972 }
973
974 static int __metadata_editor_set_mp3_metadata(metadata_editor_s* metadata, metadata_editor_attr_e attribute, const char* value)
975 {
976         int ret = METADATA_EDITOR_ERROR_NONE;
977
978         ret = __check_metadata_set_parameter(metadata);
979         metadata_editor_retvm_if(ret != METADATA_EDITOR_ERROR_NONE, ret, "fail to __check_metadata_set_parameter() [%d]", ret);
980
981         // Bring the pointer to actual file type and make tags pointers
982         TagLib::MPEG::File* _file = (TagLib::MPEG::File*)metadata->file;
983         TagLib::ID3v1::Tag* tag1 = _file->ID3v1Tag();
984         TagLib::ID3v2::Tag* tag2 = _file->ID3v2Tag(true);
985
986         metadata_editor_retvm_if(tag2 == NULL, METADATA_EDITOR_ERROR_OPERATION_FAILED, "Error. ID3v2 tag was not created. Can not proceed metadata updating");
987
988         switch (attribute) {                                    // Check which one of frame type was given for processing
989                 case METADATA_EDITOR_ATTR_ARTIST:                       return __ID3_setTwixFrameByName(metadata, tag1, tag2, "TPE1", value);
990                 case METADATA_EDITOR_ATTR_TITLE:                        return __ID3_setTwixFrameByName(metadata, tag1, tag2, "TIT2", value);
991                 case METADATA_EDITOR_ATTR_ALBUM:                        return __ID3_setTwixFrameByName(metadata, tag1, tag2, "TALB", value);
992                 case METADATA_EDITOR_ATTR_GENRE:                        return __ID3_setTwixFrameByName(metadata, tag1, tag2, "TCON", value);
993                 case METADATA_EDITOR_ATTR_AUTHOR:                       return __ID3_setFrameByName(metadata, tag2, "TCOM", value);
994                 case METADATA_EDITOR_ATTR_COPYRIGHT:            return __ID3_setFrameByName(metadata, tag2, "TCOP", value);
995                 case METADATA_EDITOR_ATTR_DATE:                 return __ID3_setTwixFrameByName(metadata, tag1, tag2, "TDRC", value);
996                 case METADATA_EDITOR_ATTR_DESCRIPTION:          return __ID3_setFrameByName(metadata, tag2, "TIT3", value);
997                 case METADATA_EDITOR_ATTR_TRACK_NUM:            return __ID3_setTwixFrameByName(metadata, tag1, tag2, "TRCK", value);
998                 case METADATA_EDITOR_ATTR_CONDUCTOR:            return __ID3_setFrameByName(metadata, tag2, "TPE3", value);
999                 case METADATA_EDITOR_ATTR_COMMENT:              return __ID3_setTwixCommentFrame(metadata, tag1, tag2, value);
1000                 case METADATA_EDITOR_ATTR_UNSYNCLYRICS: return __ID3_setLyricsFrame(metadata, tag2, value);
1001                 default:
1002                         return METADATA_EDITOR_ERROR_INVALID_PARAMETER;
1003         }
1004 }
1005
1006 static int __metadata_editor_set_mp4_metadata(metadata_editor_s* metadata, metadata_editor_attr_e attribute, const char* value)
1007 {
1008         int ret = METADATA_EDITOR_ERROR_NONE;
1009
1010         ret = __check_metadata_set_parameter(metadata);
1011         metadata_editor_retvm_if(ret != METADATA_EDITOR_ERROR_NONE, ret, "fail to __check_metadata_set_parameter() [%d]", ret);
1012
1013         switch (attribute) {                                    // Check which one of frame type was given for processing
1014         case METADATA_EDITOR_ATTR_ARTIST:                       return __MP4_updateStringItem(metadata, "\xA9""ART", value);
1015         case METADATA_EDITOR_ATTR_TITLE:                        return __MP4_updateStringItem(metadata, "\xA9""nam", value);
1016         case METADATA_EDITOR_ATTR_ALBUM:                        return __MP4_updateStringItem(metadata, "\xA9""alb", value);
1017         case METADATA_EDITOR_ATTR_GENRE:                        return __MP4_updateStringItem(metadata, "\xA9""gen", value);
1018         case METADATA_EDITOR_ATTR_AUTHOR:                       return __MP4_updateStringItem(metadata, "\xA9""wrt", value);
1019         case METADATA_EDITOR_ATTR_COPYRIGHT:            return __MP4_updateStringItem(metadata, "cprt", value);
1020         case METADATA_EDITOR_ATTR_DATE:                 return __MP4_updateStringItem(metadata, "\xA9""day", value);
1021         case METADATA_EDITOR_ATTR_DESCRIPTION:          return __MP4_updateStringItem(metadata, "desc", value);
1022         case METADATA_EDITOR_ATTR_COMMENT:              return __MP4_updateStringItem(metadata, "\xA9""cmt", value);
1023         case METADATA_EDITOR_ATTR_TRACK_NUM:            return __MP4_updateIntegerItem(metadata, "trkn", value);
1024         case METADATA_EDITOR_ATTR_CONDUCTOR:            return __MP4_updateStringItem(metadata, "cond", value);
1025         case METADATA_EDITOR_ATTR_UNSYNCLYRICS: return __MP4_updateStringItem(metadata, "\xA9""lyr", value);
1026         default:
1027                 return METADATA_EDITOR_ERROR_INVALID_PARAMETER;
1028         }
1029 }
1030
1031 #if 0
1032 static int __metadata_editor_set_flac_metadata(metadata_editor_s* metadata, metadata_editor_attr_e attribute, const char* value)
1033 {
1034         int ret = METADATA_EDITOR_ERROR_NONE;
1035
1036         ret = __check_metadata_set_parameter(metadata);
1037         metadata_editor_retvm_if(ret != METADATA_EDITOR_ERROR_NONE, ret, "fail to __check_metadata_set_parameter() [%d]", ret);
1038
1039         // Bring the pointer to actual file type and make tags pointers
1040         TagLib::FLAC::File* _file = (TagLib::FLAC::File*)metadata->file;
1041         TagLib::Ogg::XiphComment* xtag = _file->xiphComment(true);
1042         if (!xtag) {                                                            // Check if we have a valid tag for processing
1043                 metadata_editor_error("Error. Xiph Comment was not created. Can not proceed metadata updating");
1044                 return METADATA_EDITOR_ERROR_OPERATION_FAILED;
1045         }
1046         switch (attribute) {                                    // Check which one of frame type was given for processing
1047                 case METADATA_EDITOR_ATTR_ARTIST:                       return __xiph_updateFieldValue(metadata, xtag, "ARTIST", value);
1048                 case METADATA_EDITOR_ATTR_TITLE:                        return __xiph_updateFieldValue(metadata, xtag, "TITLE", value);
1049                 case METADATA_EDITOR_ATTR_ALBUM:                        return __xiph_updateFieldValue(metadata, xtag, "ALBUM", value);
1050                 case METADATA_EDITOR_ATTR_GENRE:                        return __xiph_updateFieldValue(metadata, xtag, "GENRE", value);
1051                 case METADATA_EDITOR_ATTR_AUTHOR:                       return __xiph_updateFieldValue(metadata, xtag, "COMPOSER", value);
1052                 case METADATA_EDITOR_ATTR_COPYRIGHT:                    return __xiph_updateFieldValue(metadata, xtag, "COPYRIGHT", value);
1053                 case METADATA_EDITOR_ATTR_DATE:                 return __xiph_updateFieldValue(metadata, xtag, "DATE", value);
1054                 case METADATA_EDITOR_ATTR_DESCRIPTION:          return __xiph_updateFieldValue(metadata, xtag, "DESCRIPTION", value);
1055                 case METADATA_EDITOR_ATTR_COMMENT:                      return __xiph_updateFieldValue(metadata, xtag, "COMMENT", value);
1056                 case METADATA_EDITOR_ATTR_TRACK_NUM:                    return __xiph_updateFieldValue(metadata, xtag, "TRACKNUMBER", value);
1057                 case METADATA_EDITOR_ATTR_CONDUCTOR:                    return __xiph_updateFieldValue(metadata, xtag, "CONDUCTOR", value);
1058                 case METADATA_EDITOR_ATTR_UNSYNCLYRICS:                 return __xiph_updateFieldValue(metadata, xtag, "LYRICS", value);
1059                 default:
1060                         return METADATA_EDITOR_ERROR_INVALID_PARAMETER;
1061         }
1062 }
1063
1064 static int __metadata_editor_set_ogg_vorbis_metadata(metadata_editor_s* metadata, metadata_editor_attr_e attribute, const char* value)
1065 {
1066         int ret = METADATA_EDITOR_ERROR_NONE;
1067
1068         ret = __check_metadata_set_parameter(metadata);
1069         metadata_editor_retvm_if(ret != METADATA_EDITOR_ERROR_NONE, ret, "fail to __check_metadata_set_parameter() [%d]", ret);
1070
1071         // Bring the pointer to actual file type and make tags pointers
1072         TagLib::Ogg::Vorbis::File* _file = (TagLib::Ogg::Vorbis::File*)metadata->file;
1073         TagLib::Ogg::XiphComment* xtag = _file->tag();
1074         if (!xtag) {                                                            // Check if we have a valid tag for processing
1075                 metadata_editor_error("Error. Xiph Comment was not created. Can not proceed metadata updating");
1076                 return METADATA_EDITOR_ERROR_OPERATION_FAILED;
1077         }
1078         switch (attribute) {                                    // Check which one of frame type was given for processing
1079                 case METADATA_EDITOR_ATTR_ARTIST:                       return __xiph_updateFieldValue(metadata, xtag, "ARTIST", value);
1080                 case METADATA_EDITOR_ATTR_TITLE:                        return __xiph_updateFieldValue(metadata, xtag, "TITLE", value);
1081                 case METADATA_EDITOR_ATTR_ALBUM:                        return __xiph_updateFieldValue(metadata, xtag, "ALBUM", value);
1082                 case METADATA_EDITOR_ATTR_GENRE:                        return __xiph_updateFieldValue(metadata, xtag, "GENRE", value);
1083                 case METADATA_EDITOR_ATTR_AUTHOR:                       return __xiph_updateFieldValue(metadata, xtag, "COMPOSER", value);
1084                 case METADATA_EDITOR_ATTR_COPYRIGHT:                    return __xiph_updateFieldValue(metadata, xtag, "COPYRIGHT", value);
1085                 case METADATA_EDITOR_ATTR_DATE:                 return __xiph_updateFieldValue(metadata, xtag, "DATE", value);
1086                 case METADATA_EDITOR_ATTR_DESCRIPTION:          return __xiph_updateFieldValue(metadata, xtag, "DESCRIPTION", value);
1087                 case METADATA_EDITOR_ATTR_COMMENT:                      return __xiph_updateFieldValue(metadata, xtag, "COMMENT", value);
1088                 case METADATA_EDITOR_ATTR_TRACK_NUM:                    return __xiph_updateFieldValue(metadata, xtag, "TRACKNUMBER", value);
1089                 case METADATA_EDITOR_ATTR_CONDUCTOR:                    return __xiph_updateFieldValue(metadata, xtag, "CONDUCTOR", value);
1090                 case METADATA_EDITOR_ATTR_UNSYNCLYRICS:                 return __xiph_updateFieldValue(metadata, xtag, "LYRICS", value);
1091                 default:
1092                         return METADATA_EDITOR_ERROR_INVALID_PARAMETER;
1093         }
1094 }
1095
1096 static int __metadata_editor_set_ogg_flac_metadata(metadata_editor_s* metadata, metadata_editor_attr_e attribute, const char* value)
1097 {
1098         int ret = METADATA_EDITOR_ERROR_NONE;
1099
1100         ret = __check_metadata_set_parameter(metadata);
1101         metadata_editor_retvm_if(ret != METADATA_EDITOR_ERROR_NONE, ret, "fail to __check_metadata_set_parameter() [%d]", ret);
1102
1103         // Bring the pointer to actual file type and make tags pointers
1104         TagLib::Ogg::FLAC::File* _file = (TagLib::Ogg::FLAC::File*)metadata->file;
1105         TagLib::Ogg::XiphComment* xtag = _file->tag();
1106         if (!xtag) {                                                    // Check if we have a valid tag for processing
1107                 metadata_editor_error("Error. Xiph Comment was not created. Can not proceed metadata updating");
1108                 return METADATA_EDITOR_ERROR_OPERATION_FAILED;
1109         }
1110         switch (attribute) {                                    // Check which one of frame type was given for processing
1111                 case METADATA_EDITOR_ATTR_ARTIST:                       return __xiph_updateFieldValue(metadata, xtag, "ARTIST", value);
1112                 case METADATA_EDITOR_ATTR_TITLE:                        return __xiph_updateFieldValue(metadata, xtag, "TITLE", value);
1113                 case METADATA_EDITOR_ATTR_ALBUM:                        return __xiph_updateFieldValue(metadata, xtag, "ALBUM", value);
1114                 case METADATA_EDITOR_ATTR_GENRE:                        return __xiph_updateFieldValue(metadata, xtag, "GENRE", value);
1115                 case METADATA_EDITOR_ATTR_AUTHOR:                       return __xiph_updateFieldValue(metadata, xtag, "COMPOSER", value);
1116                 case METADATA_EDITOR_ATTR_COPYRIGHT:                    return __xiph_updateFieldValue(metadata, xtag, "COPYRIGHT", value);
1117                 case METADATA_EDITOR_ATTR_DATE:                 return __xiph_updateFieldValue(metadata, xtag, "DATE", value);
1118                 case METADATA_EDITOR_ATTR_DESCRIPTION:          return __xiph_updateFieldValue(metadata, xtag, "DESCRIPTION", value);
1119                 case METADATA_EDITOR_ATTR_COMMENT:                      return __xiph_updateFieldValue(metadata, xtag, "COMMENT", value);
1120                 case METADATA_EDITOR_ATTR_TRACK_NUM:                    return __xiph_updateFieldValue(metadata, xtag, "TRACKNUMBER", value);
1121                 case METADATA_EDITOR_ATTR_CONDUCTOR:                    return __xiph_updateFieldValue(metadata, xtag, "CONDUCTOR", value);
1122                 case METADATA_EDITOR_ATTR_UNSYNCLYRICS:                 return __xiph_updateFieldValue(metadata, xtag, "LYRICS", value);
1123                 default:
1124                         return METADATA_EDITOR_ERROR_INVALID_PARAMETER;
1125         }
1126 }
1127
1128 static int __metadata_editor_set_wav_metadata(metadata_editor_s* metadata, metadata_editor_attr_e attribute, const char* value)
1129 {
1130         int ret = METADATA_EDITOR_ERROR_NONE;
1131
1132         ret = __check_metadata_set_parameter(metadata);
1133         metadata_editor_retvm_if(ret != METADATA_EDITOR_ERROR_NONE, ret, "fail to __check_metadata_set_parameter() [%d]", ret);
1134
1135         // Bring the pointer to actual file type and make tags pointers
1136         TagLib::RIFF::WAV::File* _file = (TagLib::RIFF::WAV::File*)metadata->file;
1137         TagLib::ID3v2::Tag* tag2 = _file->tag();
1138         // Check if the valid tag pointer exist
1139         if (tag2 == NULL) {
1140                 metadata_editor_error("Error. ID3v2 tag was not created. Can not proceed metadata updating");
1141                 return METADATA_EDITOR_ERROR_OPERATION_FAILED;
1142         }
1143
1144         switch (attribute) {                                    // Check which one of frame type was given for processing
1145                 case METADATA_EDITOR_ATTR_ARTIST:                       return __ID3_setFrameByName(metadata, tag2, "TPE1", value);
1146                 case METADATA_EDITOR_ATTR_TITLE:                        return __ID3_setFrameByName(metadata, tag2, "TIT2", value);
1147                 case METADATA_EDITOR_ATTR_ALBUM:                        return __ID3_setFrameByName(metadata, tag2, "TALB", value);
1148                 case METADATA_EDITOR_ATTR_GENRE:                        return __ID3_setFrameByName(metadata, tag2, "TCON", value);
1149                 case METADATA_EDITOR_ATTR_AUTHOR:                       return __ID3_setFrameByName(metadata, tag2, "TCOM", value);
1150                 case METADATA_EDITOR_ATTR_COPYRIGHT:            return __ID3_setFrameByName(metadata, tag2, "TCOP", value);
1151                 case METADATA_EDITOR_ATTR_DATE:                 return __ID3_setFrameByName(metadata, tag2, "TDRC", value);
1152                 case METADATA_EDITOR_ATTR_DESCRIPTION:          return __ID3_setFrameByName(metadata, tag2, "TIT3", value);
1153                 case METADATA_EDITOR_ATTR_TRACK_NUM:            return __ID3_setFrameByName(metadata, tag2, "TRCK", value);
1154                 case METADATA_EDITOR_ATTR_CONDUCTOR:            return __ID3_setFrameByName(metadata, tag2, "TPE3", value);
1155                 case METADATA_EDITOR_ATTR_COMMENT:              return __ID3_setTwixCommentFrame(metadata, NULL, tag2, value);
1156                 case METADATA_EDITOR_ATTR_UNSYNCLYRICS: return __ID3_setLyricsFrame(metadata, tag2, value);
1157                 default:
1158                         return METADATA_EDITOR_ERROR_INVALID_PARAMETER;
1159         }
1160 }
1161 #endif
1162
1163 // *** This function is used to modify the metadata (frame in tag). But it does not apply changes to file *** //
1164 extern "C" int metadata_editor_set_metadata(metadata_editor_h metadata, metadata_editor_attr_e attribute, const char* value) {
1165
1166         metadata_editor_s* _metadata = (metadata_editor_s*) metadata;
1167         metadata_editor_retvm_if(!_metadata, METADATA_EDITOR_ERROR_INVALID_PARAMETER, "Invalid metadata");
1168
1169         switch (_metadata->filetype) {
1170         case METADATA_EDITOR_FORMAT_MP3:
1171                 return __metadata_editor_set_mp3_metadata(_metadata, attribute, value);
1172
1173         case METADATA_EDITOR_FORMAT_MP4:
1174                 return __metadata_editor_set_mp4_metadata(_metadata, attribute, value);
1175
1176 #if 0
1177         case METADATA_EDITOR_FORMAT_FLAC:
1178                 return __metadata_editor_set_flac_metadata(_metadata, attribute, value);
1179
1180         case METADATA_EDITOR_FORMAT_OGG_VORBIS:
1181                 return __metadata_editor_set_ogg_vorbis_metadata(_metadata, attribute, value);
1182
1183         case METADATA_EDITOR_FORMAT_OGG_FLAC:
1184                 return __metadata_editor_set_ogg_flac_metadata(_metadata, attribute, value);
1185
1186         case METADATA_EDITOR_FORMAT_WAV:
1187                 return __metadata_editor_set_wav_metadata(_metadata, attribute, value);
1188
1189 #endif
1190         default:
1191                 metadata_editor_error("Wrong file type");
1192                 return METADATA_EDITOR_ERROR_INVALID_PARAMETER;
1193         }
1194 }
1195
1196 // *** This function apply all changes done in the tag(s) and update them to file *** //
1197 extern "C" int metadata_editor_update_metadata(metadata_editor_h metadata) {
1198         int ret = METADATA_EDITOR_ERROR_NONE;
1199         metadata_editor_s* _metadata = (metadata_editor_s*) metadata;
1200
1201         ret = __check_metadata_set_parameter(_metadata);
1202         metadata_editor_retvm_if(ret != METADATA_EDITOR_ERROR_NONE, ret, "fail to __check_metadata_set_parameter() [%d]", ret);
1203
1204         switch (_metadata->filetype) {
1205         case METADATA_EDITOR_FORMAT_MP3: {
1206                 TagLib::MPEG::File* _file = (TagLib::MPEG::File*)_metadata->file;
1207                 TagLib::ID3v1::Tag* tag1 = _file->ID3v1Tag();
1208
1209                 if (!tag1 || tag1->isEmpty()) { // If no ID3v1 tag - prevent its creation
1210                         if (_file->save(TagLib::MPEG::File::ID3v2 | TagLib::MPEG::File::APE))
1211                                 return METADATA_EDITOR_ERROR_NONE;
1212                 } else {        // otherwise - save all tags in file
1213                         if (_file->save(TagLib::MPEG::File::AllTags))
1214                                 return METADATA_EDITOR_ERROR_NONE;
1215                 }
1216
1217                 return METADATA_EDITOR_ERROR_OPERATION_FAILED;
1218         }
1219
1220         case METADATA_EDITOR_FORMAT_MP4: {
1221 #if 0
1222         case METADATA_EDITOR_FORMAT_FLAC:
1223         case METADATA_EDITOR_FORMAT_OGG_VORBIS:
1224         case METADATA_EDITOR_FORMAT_OGG_FLAC:
1225         case METADATA_EDITOR_FORMAT_WAV:
1226 #endif
1227                 if (_metadata->file->save())
1228                         return METADATA_EDITOR_ERROR_NONE;
1229
1230                 return METADATA_EDITOR_ERROR_OPERATION_FAILED;
1231         }
1232
1233         default:
1234                 metadata_editor_error("Wrong file type");
1235                 return METADATA_EDITOR_ERROR_INVALID_PARAMETER;
1236         }
1237 }
1238
1239 static char * __get_mime_type(const TagLib::String& mime_type)
1240 {
1241         if (mime_type == MIME_TYPE_JPEG || mime_type == MIME_TYPE_PNG)
1242                 return g_strdup(mime_type.toCString());
1243
1244         return NULL;
1245 }
1246
1247 static char * __get_mime_type_from_cover_art(const TagLib::MP4::CoverArt& cover_art)
1248 {
1249         if (cover_art.format() == TagLib::MP4::CoverArt::JPEG)
1250                 return g_strdup(MIME_TYPE_JPEG);
1251         else if (cover_art.format() == TagLib::MP4::CoverArt::PNG)
1252                 return g_strdup(MIME_TYPE_PNG);
1253
1254         return NULL;
1255 }
1256
1257 static int __get_APIC(TagLib::ID3v2::Tag* tag, int index, void **picture, int *size, char **mime_type)
1258 {
1259         metadata_editor_retvm_if(!tag, METADATA_EDITOR_ERROR_OPERATION_FAILED, "Error. No ID3v2 tag in file.");
1260
1261         TagLib::ID3v2::FrameList lst = tag->frameListMap()["APIC"];
1262
1263         // Check if there are pictures in the tag
1264         if (lst.isEmpty()) {
1265                 metadata_editor_error("No pictures in file");
1266                 return METADATA_EDITOR_ERROR_OPERATION_FAILED;
1267         }
1268
1269         // Check if index is correct or not
1270         if ((index < 0) || (lst.size() <= (uint)index)) {
1271                 metadata_editor_error("Index of picture is out of range");
1272                 return METADATA_EDITOR_ERROR_INVALID_PARAMETER;
1273         }
1274
1275         metadata_editor_info("There are %u pictures in file. Start of picture number %d extraction", lst.size(), index);
1276
1277         auto pictureFrame = static_cast<TagLib::ID3v2::AttachedPictureFrame*>(lst[index]);
1278
1279         uint pictureSize = pictureFrame->picture().size();
1280         metadata_editor_retvm_if(pictureSize == 0, METADATA_EDITOR_ERROR_OPERATION_FAILED, "Size of picture is 0");
1281
1282         *picture = g_memdup(pictureFrame->picture().data(), pictureSize);
1283         *size = pictureSize;
1284         *mime_type = __get_mime_type(pictureFrame->mimeType());
1285
1286         return METADATA_EDITOR_ERROR_NONE;
1287 }
1288
1289 static int __get_mp3_picture(metadata_editor_s* metadata, int index, void **picture, int *size, char **mime_type)
1290 {
1291         return __get_APIC(dynamic_cast<TagLib::MPEG::File*>(metadata->file)->ID3v2Tag(), index, picture, size, mime_type);
1292 }
1293
1294 static int __get_mp4_picture(metadata_editor_s* metadata, int index, void **picture, int *size, char **mime_type)
1295 {
1296         auto tag = dynamic_cast<TagLib::MP4::Tag*>(metadata->file->tag());
1297         metadata_editor_retvm_if(!tag, METADATA_EDITOR_ERROR_OPERATION_FAILED, "Tag does not exist");
1298
1299         if (!(tag->contains("covr"))) {
1300                 metadata_editor_error("No item <covr> in file. No pictures in file");
1301                 return METADATA_EDITOR_ERROR_OPERATION_FAILED;
1302         }
1303
1304         TagLib::MP4::CoverArtList lst = tag->item("covr").toCoverArtList();
1305
1306         // Check if the index is in range of CoverArtList Item
1307         if ((index < 0) || ((uint)index >= lst.size())) {
1308                 metadata_editor_error("Index of picture is out of range");
1309                 return METADATA_EDITOR_ERROR_INVALID_PARAMETER;
1310         }
1311
1312         auto pictureFrame = static_cast<TagLib::MP4::CoverArt>(lst[index]);
1313
1314         int pictureSize = pictureFrame.data().size();
1315         metadata_editor_retvm_if(pictureSize == 0, METADATA_EDITOR_ERROR_OPERATION_FAILED, "Size of picture is 0");
1316
1317         *picture = g_memdup(pictureFrame.data().data(), pictureSize);
1318         *size = pictureSize;
1319         *mime_type = __get_mime_type_from_cover_art(pictureFrame);
1320
1321         return METADATA_EDITOR_ERROR_NONE;
1322 }
1323
1324 #if 0
1325 static int __get_flac_picture(metadata_editor_s* metadata, int index, void **picture, int *size, char **mime_type)
1326 {
1327         TagLib::FLAC::File* _file = (TagLib::FLAC::File*) metadata->file;
1328         TagLib::List<TagLib::FLAC::Picture*> lst = _file->pictureList();
1329
1330         if (lst.isEmpty()) {
1331                 metadata_editor_error("No pictures in FLAC file");
1332                 return METADATA_EDITOR_ERROR_OPERATION_FAILED;
1333         }
1334
1335         // Check if the index is in range of CoverArtList Item
1336         if ((index < 0) || ((uint)index >= lst.size())) {
1337                 metadata_editor_error("Index of picture is out of range");
1338                 return METADATA_EDITOR_ERROR_INVALID_PARAMETER;
1339         }
1340
1341         auto pictureFrame = static_cast<TagLib::FLAC::Picture*>(lst[index]);
1342
1343         int pictureSize = pictureFrame->data().size();
1344         metadata_editor_retvm_if(pictureSize == 0, METADATA_EDITOR_ERROR_OPERATION_FAILED, "Size of picture is 0");
1345
1346         *picture = g_memdup(pictureFrame->data().data(), pictureSize);
1347         *size = pictureSize;
1348         *mime_type = __get_mime_type(pictureFrame->mimeType());
1349
1350         return METADATA_EDITOR_ERROR_NONE;
1351 }
1352
1353 static int __get_wav_picture(metadata_editor_s* metadata, int index, void **picture, int *size, char **mime_type)
1354 {
1355         TagLib::RIFF::WAV::File* _file = (TagLib::RIFF::WAV::File*)metadata->file;
1356
1357         return __get_APIC(_file->tag(), index, picture, size, mime_type);
1358 }
1359 #endif
1360
1361 // *** This function returns buffer with picture under the specified index and buffer's (picture's) size *** //
1362 extern "C" int metadata_editor_get_picture(metadata_editor_h metadata, int index, void **picture, int *size, char **mime_type) {
1363         int ret = METADATA_EDITOR_ERROR_NONE;
1364         metadata_editor_s* _metadata = (metadata_editor_s*) metadata;
1365
1366         ret = __check_metadata_get_parameter(_metadata, mime_type);
1367         metadata_editor_retvm_if(ret != METADATA_EDITOR_ERROR_NONE, ret, "fail to __check_metadata_get_parameter() [%d]", ret);
1368         metadata_editor_retvm_if(!picture, METADATA_EDITOR_ERROR_INVALID_PARAMETER, "Invalid picture");
1369         metadata_editor_retvm_if(!size, METADATA_EDITOR_ERROR_INVALID_PARAMETER, "Invalid size");
1370
1371         switch (_metadata->filetype) {                                                                  // Process the file according to the specified file type
1372         case METADATA_EDITOR_FORMAT_MP3:
1373                 return __get_mp3_picture(_metadata, index, picture, size, mime_type);
1374
1375         case METADATA_EDITOR_FORMAT_MP4:
1376                 return __get_mp4_picture(_metadata, index, picture, size, mime_type);
1377
1378 #if 0
1379         case METADATA_EDITOR_FORMAT_FLAC:
1380                 return __get_flac_picture(_metadata, index, picture, size, mime_type);
1381
1382         case METADATA_EDITOR_FORMAT_WAV:
1383                 return __get_wav_picture(_metadata, index, picture, size, mime_type);
1384 #endif
1385         default:
1386                 metadata_editor_error("Wrong file type");
1387                 return METADATA_EDITOR_ERROR_INVALID_PARAMETER;
1388         }
1389 }
1390
1391 static int __append_APIC(TagLib::ID3v2::Tag* tag, void *picture, size_t size, const char *mime_type)
1392 {
1393         metadata_editor_retvm_if(!tag, METADATA_EDITOR_ERROR_OPERATION_FAILED, "Error. No ID3v2 tag in file.");
1394
1395         auto pictureFrame = new TagLib::ID3v2::AttachedPictureFrame();
1396
1397         metadata_editor_info("New APIC frame will be added to the ID3v2 tag");
1398
1399         pictureFrame->setPicture(TagLib::ByteVector((char*)picture, size));
1400         pictureFrame->setType(TagLib::ID3v2::AttachedPictureFrame::FrontCover);
1401         pictureFrame->setMimeType(mime_type);
1402
1403         tag->addFrame(pictureFrame);
1404
1405         return METADATA_EDITOR_ERROR_NONE;
1406
1407 }
1408 static int __append_mp3_picture(metadata_editor_s* metadata, void *picture ,size_t size, const char *mime_type)
1409 {
1410         return __append_APIC(dynamic_cast<TagLib::MPEG::File*>(metadata->file)->ID3v2Tag(true), picture, size, mime_type);
1411 }
1412
1413 static int __append_mp4_picture(metadata_editor_s* metadata, void *picture, size_t size, const char *mime_type)
1414 {
1415         auto tag = dynamic_cast<TagLib::MP4::Tag*>(metadata->file->tag());
1416         metadata_editor_retvm_if(!tag, METADATA_EDITOR_ERROR_OPERATION_FAILED, "Tag does not exist");
1417
1418         TagLib::MP4::CoverArtList lst;
1419         TagLib::MP4::CoverArt::Format format = TagLib::MP4::CoverArt::Unknown;
1420         if (strncmp(mime_type, MIME_TYPE_JPEG, strlen(MIME_TYPE_JPEG)) == 0)
1421                 format = TagLib::MP4::CoverArt::JPEG;
1422         else if (strncmp(mime_type, MIME_TYPE_PNG, strlen(MIME_TYPE_PNG)) == 0)
1423                 format = TagLib::MP4::CoverArt::PNG;
1424
1425         if (tag->contains("covr")) {
1426                 metadata_editor_info("The item <covr> exists. Adding picture");
1427                 lst = tag->item("covr").toCoverArtList();
1428         }
1429
1430         lst.append(TagLib::MP4::CoverArt(format, TagLib::ByteVector((char*)picture, size)));
1431         tag->setItem("covr", lst);
1432
1433         return METADATA_EDITOR_ERROR_NONE;
1434 }
1435
1436 #if 0
1437 static int __append_flac_picture(metadata_editor_s* metadata, void *picture, size_t size, const char *mime_type)
1438 {
1439         TagLib::FLAC::File* _file = (TagLib::FLAC::File*) metadata->file;
1440         auto frontCover = new TagLib::FLAC::Picture;
1441
1442         metadata_editor_debug_fenter();
1443
1444         frontCover->setData(TagLib::ByteVector((char*)picture, size));
1445         frontCover->setType(TagLib::FLAC::Picture::FrontCover);
1446         frontCover->setMimeType(mime_type);
1447
1448         _file->addPicture(frontCover);
1449
1450         return METADATA_EDITOR_ERROR_NONE;
1451 }
1452
1453 static int __append_wav_picture(metadata_editor_s* metadata, void *picture, size_t size, const char *mime_type)
1454 {
1455         return __append_APIC(dynamic_cast<TagLib::ID3v2::Tag*>(metadata->file->tag()), picture, size, mime_type);
1456 }
1457 #endif
1458
1459 // *** This function appends a cover art picture to the file *** //
1460 extern "C" int metadata_editor_append_picture(metadata_editor_h metadata, const char *path) {
1461         int ret = METADATA_EDITOR_ERROR_NONE;
1462         void *picture = NULL;
1463         size_t size = 0;
1464         char *mime_type = NULL;
1465
1466         metadata_editor_s* _metadata = (metadata_editor_s*) metadata;
1467
1468         ret = __check_metadata_set_parameter(_metadata);
1469         metadata_editor_retvm_if(ret != METADATA_EDITOR_ERROR_NONE, ret, "fail to __check_metadata_set_parameter() [%d]", ret);
1470         metadata_editor_retvm_if(!path, METADATA_EDITOR_ERROR_INVALID_PARAMETER, "Invalid path");
1471
1472         ret = __metadata_editor_get_picture_info(path, &picture, &size, &mime_type);
1473         metadata_editor_retvm_if(ret != METADATA_EDITOR_ERROR_NONE, METADATA_EDITOR_ERROR_PERMISSION_DENIED, "File does not exist or you have no rights to open it");
1474
1475         switch (_metadata->filetype) {
1476                 case METADATA_EDITOR_FORMAT_MP3:
1477                         ret = __append_mp3_picture(_metadata, picture, size, mime_type);
1478                         break;
1479
1480                 case METADATA_EDITOR_FORMAT_MP4:
1481                         ret = __append_mp4_picture(_metadata, picture, size, mime_type);
1482                         break;
1483
1484 #if 0
1485                 case METADATA_EDITOR_FORMAT_FLAC:
1486                         ret = __append_flac_picture(_metadata, picture, size, mime_type);
1487                         break;
1488
1489                 case METADATA_EDITOR_FORMAT_WAV:
1490                         ret = __append_wav_picture(_metadata, picture, size, mime_type);
1491                         break;
1492 #endif
1493                 default: {
1494                         metadata_editor_error("Wrong file type");
1495                         ret = METADATA_EDITOR_ERROR_NOT_SUPPORTED;
1496                         break;
1497                 }
1498         }
1499
1500         META_SAFE_FREE(picture);
1501         g_free(mime_type);
1502
1503         return ret;
1504 }
1505
1506 static int __remove_APIC(TagLib::ID3v2::Tag* tag, int index)
1507 {
1508         metadata_editor_retvm_if(tag == NULL, METADATA_EDITOR_ERROR_OPERATION_FAILED, "Error. ID3v2 tag was not created. Can not proceed metadata updating");
1509
1510         TagLib::ID3v2::FrameList lst = tag->frameListMap()["APIC"];
1511         metadata_editor_retvm_if(lst.isEmpty(), METADATA_EDITOR_ERROR_OPERATION_FAILED, "No pictures in file");
1512
1513         if ((index < 0) || ((uint)index >= lst.size())) {
1514                 metadata_editor_error("Index of picture is out of range");
1515                 return METADATA_EDITOR_ERROR_INVALID_PARAMETER;
1516         }
1517
1518         tag->removeFrame(lst[index]);
1519
1520         return METADATA_EDITOR_ERROR_NONE;
1521 }
1522 static int __remove_mp3_picture(metadata_editor_s* metadata, int index)
1523 {
1524         return __remove_APIC(dynamic_cast<TagLib::MPEG::File*>(metadata->file)->ID3v2Tag(true), index);
1525 }
1526
1527 static int __remove_mp4_picture(metadata_editor_s* metadata, int index)
1528 {
1529         auto tag = dynamic_cast<TagLib::MP4::Tag*>(metadata->file->tag());
1530         metadata_editor_retvm_if(!tag, METADATA_EDITOR_ERROR_OPERATION_FAILED, "Tag does not exist");
1531
1532         if (!(tag->contains("covr"))) {
1533                 metadata_editor_error("No item <covr> in file. No pictures in file");
1534                 return METADATA_EDITOR_ERROR_OPERATION_FAILED;
1535         }
1536
1537         TagLib::MP4::CoverArtList lst = tag->item("covr").toCoverArtList();
1538
1539         // Check if the index is in range of CoverArtList Item
1540         if ((index < 0) || ((uint)index >= lst.size())) {
1541                 metadata_editor_error("Index of picture is out of range");
1542                 return METADATA_EDITOR_ERROR_INVALID_PARAMETER;
1543         }
1544
1545         metadata_editor_info("The picture number %d will be deleted", index);
1546         int i = 0;
1547         for (TagLib::MP4::CoverArtList::Iterator picIt = lst.begin(); picIt != lst.end(); ++picIt, ++i) {
1548                 if (i != index) continue;
1549                 lst.erase(picIt);
1550                         break;
1551         }
1552
1553         tag->setItem("covr", lst);      //?? FIX ME!
1554
1555         return METADATA_EDITOR_ERROR_NONE;
1556 }
1557
1558 #if 0
1559 static int __remove_flac_picture(metadata_editor_s* metadata, int index)
1560 {
1561         TagLib::FLAC::File* _file = (TagLib::FLAC::File*) metadata->file;
1562         TagLib::List<TagLib::FLAC::Picture*> lst = _file->pictureList();
1563
1564         if (lst.isEmpty()) {
1565                 metadata_editor_error("No pictures in file. Nothing to delete");
1566                 return METADATA_EDITOR_ERROR_OPERATION_FAILED;
1567         }
1568
1569         // Check if the index is in range of CoverArtList Item
1570         if ((index < 0) || ((uint)index >= lst.size())) {
1571                 metadata_editor_error("Index of picture is out of range");
1572                 return METADATA_EDITOR_ERROR_INVALID_PARAMETER;
1573         }
1574
1575         metadata_editor_info("The picture number %d will be deleted", index);
1576         int i = 0;
1577         for (TagLib::List<TagLib::FLAC::Picture*>::Iterator picIt = lst.begin(); picIt != lst.end(); ++picIt, ++i) {
1578                 if (i != index) continue;
1579                 _file->removePicture(*picIt, true);
1580                 break;
1581         }
1582
1583         return METADATA_EDITOR_ERROR_NONE;
1584 }
1585
1586 static int __remove_wav_picture(metadata_editor_s* metadata, int index)
1587 {
1588         return __remove_APIC(dynamic_cast<TagLib::ID3v2::Tag*>(metadata->file->tag()), index);
1589 }
1590 #endif
1591
1592 // *** This function is used to delete picture with specified index *** //
1593 extern "C" int metadata_editor_remove_picture(metadata_editor_h metadata, int index) {
1594         int ret = METADATA_EDITOR_ERROR_NONE;
1595         metadata_editor_s* _metadata = (metadata_editor_s*) metadata;
1596
1597         ret = __check_metadata_set_parameter(_metadata);
1598         metadata_editor_retvm_if(ret != METADATA_EDITOR_ERROR_NONE, ret, "fail to __check_metadata_set_parameter() [%d]", ret);
1599
1600         switch (_metadata->filetype) {
1601                 case METADATA_EDITOR_FORMAT_MP3:
1602                         return __remove_mp3_picture(_metadata, index);
1603
1604                 case METADATA_EDITOR_FORMAT_MP4:
1605                         return __remove_mp4_picture(_metadata, index);
1606 #if 0
1607                 case METADATA_EDITOR_FORMAT_FLAC:
1608                         return __remove_flac_picture(_metadata, index);
1609
1610                 case METADATA_EDITOR_FORMAT_WAV:
1611                         return __remove_wav_picture(_metadata, index);
1612 #endif
1613                 default:
1614                         metadata_editor_error("Wrong file type");
1615                         return METADATA_EDITOR_ERROR_INVALID_PARAMETER;
1616         }
1617 }
1618
1619 extern "C" int metadata_editor_destroy(metadata_editor_h metadata) {
1620         metadata_editor_s *_metadata = (metadata_editor_s*)metadata;
1621
1622         metadata_editor_retvm_if(!_metadata, METADATA_EDITOR_ERROR_INVALID_PARAMETER, "Invalid metadata");
1623
1624         if (_metadata->file)
1625                 delete _metadata->file;
1626
1627         g_free(_metadata);
1628
1629         return METADATA_EDITOR_ERROR_NONE;
1630 }