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