2 * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #include <metadata_editor.h>
18 #include <metadata_editor_private.h>
20 #include <sys/types.h>
26 #define MIME_TYPE_JPEG "image/jpeg"
27 #define MIME_TYPE_PNG "image/png"
29 static int __ID3_getTwixFrameByName(metadata_editor_s* _metadata, TagLib::ID3v1::Tag* tag1, TagLib::ID3v2::Tag* tag2, const char* frameID, char** value);
30 static int __ID3_setTwixFrameByName(metadata_editor_s* _metadata, TagLib::ID3v1::Tag* tag1, TagLib::ID3v2::Tag* tag2, const char* frameID, const char* value);
31 static int __ID3_getFrameByName(metadata_editor_s* _metadata, TagLib::ID3v2::Tag* tag2, const char* frameID, char** value);
32 static int __ID3_setFrameByName(metadata_editor_s* _metadata, TagLib::ID3v2::Tag* tag2, const char* frameID, const char* value);
33 static int __ID3_getLyricsFrame(metadata_editor_s* _metadata, TagLib::ID3v2::Tag* tag2, char** value);
34 static int __ID3_setTwixCommentFrame(metadata_editor_s* _metadata, TagLib::ID3v1::Tag* tag1, TagLib::ID3v2::Tag* tag2, const char* value);
35 static int __ID3_setLyricsFrame(metadata_editor_s* _metadata, TagLib::ID3v2::Tag* tag2, const char* value);
36 static int __MP4_getStringItem(metadata_editor_s* _metadata, const char* itemname, char** value);
37 static int __MP4_getIntegerItem(metadata_editor_s* _metadata, const char* itemname, char** value);
38 static int __MP4_updateStringItem(metadata_editor_s* _metadata, const char* itemname, const char* value);
39 static int __MP4_updateIntegerItem(metadata_editor_s* _metadata, const char* itemname, const char* value);
41 static int __xiph_getFieldValue(metadata_editor_s* _metadata, TagLib::Ogg::XiphComment* xtag, const char* fieldname, char** value);
42 static int __xiph_updateFieldValue(metadata_editor_s* _metadata, TagLib::Ogg::XiphComment* xtag, const char* fieldname, const char* value);
45 METADATA_EDITOR_FORMAT_MP3 = 0, /**< MP3 File */
46 METADATA_EDITOR_FORMAT_MP4, /**< MP4 File */
47 METADATA_EDITOR_FORMAT_FLAC, /**< FLAC File */
48 METADATA_EDITOR_FORMAT_OGG_VORBIS, /**< Vorbis Audio in Ogg container */
49 METADATA_EDITOR_FORMAT_OGG_FLAC, /**< FLAC Audio in Ogg container */
50 METADATA_EDITOR_FORMAT_WAV, /**< WAV file */
51 METADATA_EDITOR_FORMAT_NOTYPE = 0xFF /**< Error type. File type is not correct or not specified */
52 } metadata_editor_format_e;
54 static int __check_metadata_parameter(metadata_editor_s *metadata)
56 metadata_editor_retvm_if(!metadata, METADATA_EDITOR_ERROR_INVALID_PARAMETER, "Invalid metadata");
57 metadata_editor_retvm_if(!metadata->file, METADATA_EDITOR_ERROR_INVALID_PARAMETER, "File loading fail");
59 return METADATA_EDITOR_ERROR_NONE;
62 static int __check_metadata_set_parameter(metadata_editor_s *metadata)
64 int ret = METADATA_EDITOR_ERROR_NONE;
66 ret = __check_metadata_parameter(metadata);
67 metadata_editor_retvm_if(ret != METADATA_EDITOR_ERROR_NONE, ret, "fail to __check_metadata_parameter");
69 metadata_editor_retvm_if(metadata->file->readOnly(), METADATA_EDITOR_ERROR_PERMISSION_DENIED, "File is readonly. Unable to modify");
71 return METADATA_EDITOR_ERROR_NONE;
74 static int __check_metadata_get_parameter(metadata_editor_s *metadata, char **value)
76 int ret = METADATA_EDITOR_ERROR_NONE;
78 ret = __check_metadata_parameter(metadata);
79 metadata_editor_retvm_if(ret != METADATA_EDITOR_ERROR_NONE, ret, "fail to __check_metadata_parameter");
81 metadata_editor_retvm_if(!value, METADATA_EDITOR_ERROR_INVALID_PARAMETER, "Invalid value");
83 return METADATA_EDITOR_ERROR_NONE;
86 static int __ID3_getTwixFrameByName(metadata_editor_s *_metadata, TagLib::ID3v1::Tag *tag1, TagLib::ID3v2::Tag *tag2, const char *frameID, char **value)
88 int ret = METADATA_EDITOR_ERROR_NONE;
90 ret = __check_metadata_get_parameter(_metadata, value);
91 metadata_editor_retvm_if(ret != METADATA_EDITOR_ERROR_NONE, ret, "fail to __check_metadata_get_parameter() [%d]", ret);
92 metadata_editor_retvm_if(!frameID, METADATA_EDITOR_ERROR_INVALID_PARAMETER, "Invalid frameID");
94 if (tag2 && !(tag2->frameListMap()[frameID].isEmpty())) {
95 metadata_editor_info("The frame %s exists in ID3v2 tag", frameID);
96 *value = g_strdup(tag2->frameListMap()[frameID][0]->toString().toCString(true));
97 return METADATA_EDITOR_ERROR_NONE;
100 metadata_editor_info("The frame %s in ID3v2 tag is empty", frameID);
102 if (!tag1 || tag1->isEmpty()) {
103 metadata_editor_info("The frame %s in ID3v1 tag is empty as well", frameID);
104 return METADATA_EDITOR_ERROR_NONE;
107 metadata_editor_info("Reading data from ID3v1 tag");
109 if (!strcmp(frameID, "TPE1")) /* artist */
110 *value = g_strdup(tag1->artist().toCString(true));
111 else if (!strcmp(frameID, "TALB")) /* album */
112 *value = g_strdup(tag1->album().toCString(true));
113 else if (!strcmp(frameID, "COMM")) /* comment */
114 *value = g_strdup(tag1->comment().toCString(true));
115 else if (!strcmp(frameID, "TCON")) /* genre */
116 *value = g_strdup(tag1->genre().toCString(true));
117 else if (!strcmp(frameID, "TIT2")) /* title */
118 *value = g_strdup(tag1->title().toCString(true));
119 else if (!strcmp(frameID, "TRCK")) /* track */
120 *value = g_strdup_printf("%u", tag1->track());
121 else if (!strcmp(frameID, "TDRC")) /* data (year) */
122 *value = g_strdup_printf("%u", tag1->year());
124 metadata_editor_debug("The desired frame was not found");
126 return METADATA_EDITOR_ERROR_NONE;
130 // *** This is an auxiliary function that is used to write the new value to the frame *** //
131 // *** It operates with frames that exists both in ID3v1 and ID3v2 tags *** //
132 static int __ID3_setTwixFrameByName(metadata_editor_s* _metadata, TagLib::ID3v1::Tag* tag1, TagLib::ID3v2::Tag* tag2, const char* frameID, const char* value) {
133 int ret = METADATA_EDITOR_ERROR_NONE;
135 ret = __check_metadata_set_parameter(_metadata);
136 metadata_editor_retvm_if(ret != METADATA_EDITOR_ERROR_NONE, ret, "fail to __check_metadata_set_parameter() [%d]", ret);
137 metadata_editor_retvm_if(!frameID, METADATA_EDITOR_ERROR_INVALID_PARAMETER, "Invalid frameID");
138 metadata_editor_retvm_if(!tag2, METADATA_EDITOR_ERROR_OPERATION_FAILED, "Error. ID3v2 tag was not created. Can not proceed metadata updating");
140 // If the pointer is NULL or c-string is empty - handle as request for deletion
141 if (!value || (*value == '\0')) {
142 metadata_editor_info("Request for frame %s deletion", frameID);
143 tag2->removeFrames(frameID);
144 if (tag1 && !tag1->isEmpty()) {
145 if (!strcmp(frameID, "TPE1"))
147 else if (!strcmp(frameID, "TALB"))
149 else if (!strcmp(frameID, "TCON"))
151 else if (!strcmp(frameID, "TIT2"))
153 else if (!strcmp(frameID, "TRCK"))
155 else if (!strcmp(frameID, "TDRC"))
159 return METADATA_EDITOR_ERROR_NONE;
162 // Check if the frame is empty (must create the frame before writing the data)
163 if (tag2->frameListMap()[frameID].isEmpty()) {
164 metadata_editor_info("The frame %s does not exist. Creating", frameID);
165 // This is a common frame type for textural frames except comment frame
166 auto fr = new TagLib::ID3v2::TextIdentificationFrame(frameID);
168 fr->setTextEncoding(TagLib::String::UTF8);
169 fr->setText(TagLib::String(value, TagLib::String::UTF8));
171 } else { // if not - just modify the data in the existing frame
172 metadata_editor_info("The frame %s exists. Changing", frameID);
173 tag2->frameListMap()[frameID][0]->setText(TagLib::String(value, TagLib::String::UTF8));
176 if (tag1 && !tag1->isEmpty()) { // Check if ID3v1 tag exists. Must copy data if yes.
177 metadata_editor_info("ID3v1 tag also exists. Copying frame");
178 if (!strcmp(frameID, "TPE1"))
179 tag1->setArtist(value);
180 else if (!strcmp(frameID, "TALB"))
181 tag1->setAlbum(value);
182 else if (!strcmp(frameID, "TCON")) // Genre in ID3v1 is enumeration, so can not write it with "value"
184 else if (!strcmp(frameID, "TIT2"))
185 tag1->setTitle(value);
186 else if (!strcmp(frameID, "TRCK"))
187 tag1->setTrack(atoi(value));
188 else if (!strcmp(frameID, "TDRC"))
189 tag1->setYear(atoi(value));
192 return METADATA_EDITOR_ERROR_NONE;
195 static int __ID3_getFrameByName(metadata_editor_s *_metadata, TagLib::ID3v2::Tag *tag2, const char *frameID, char **value)
197 int ret = METADATA_EDITOR_ERROR_NONE;
199 ret = __check_metadata_get_parameter(_metadata, value);
200 metadata_editor_retvm_if(ret != METADATA_EDITOR_ERROR_NONE, ret, "fail to __check_metadata_get_parameter() [%d]", ret);
201 metadata_editor_retvm_if(!frameID, METADATA_EDITOR_ERROR_INVALID_PARAMETER, "Invalid frameID");
202 metadata_editor_retvm_if(!tag2 || tag2->frameListMap()[frameID].isEmpty(), METADATA_EDITOR_ERROR_NONE, "The frame %s does not exist", frameID);
204 metadata_editor_info("The frame %s exists", frameID);
206 *value = g_strdup(tag2->frameListMap()[frameID][0]->toString().toCString(true));
208 return METADATA_EDITOR_ERROR_NONE;
211 // *** This function writes frames that exist only in ID3v2 tag *** //
212 static int __ID3_setFrameByName(metadata_editor_s* _metadata, TagLib::ID3v2::Tag* tag2, const char* frameID, const char* value) {
213 int ret = METADATA_EDITOR_ERROR_NONE;
215 ret = __check_metadata_set_parameter(_metadata);
216 metadata_editor_retvm_if(ret != METADATA_EDITOR_ERROR_NONE, ret, "fail to __check_metadata_set_parameter() [%d]", ret);
217 metadata_editor_retvm_if(!frameID, METADATA_EDITOR_ERROR_INVALID_PARAMETER, "Invalid frameID");
218 metadata_editor_retvm_if(!tag2, METADATA_EDITOR_ERROR_OPERATION_FAILED, "Error. ID3v2 tag was not created. Can not proceed metadata updating");
220 // If the pointer is NULL or c-string is empty - handle as request for deletion
221 if (!value || (*value == '\0')) {
222 metadata_editor_info("Request for frame %s deletion", frameID);
223 tag2->removeFrames(frameID);
224 return METADATA_EDITOR_ERROR_NONE;
227 // Check if the ID3v2 tag exists
228 if (tag2->frameListMap()[frameID].isEmpty()) {
229 metadata_editor_info("The frame %s does not exist. Creating", frameID);
230 // This is a common frame type for textural frames except comment frame
231 auto fr = new TagLib::ID3v2::TextIdentificationFrame(frameID);
233 fr->setTextEncoding(TagLib::String::UTF8);
234 fr->setText(TagLib::String(value, TagLib::String::UTF8));
236 } else { // if not - just modify the data in the existing frame
237 metadata_editor_info("The frame %s exists. Changing", frameID);
238 tag2->frameListMap()[frameID][0]->setText(TagLib::String(value, TagLib::String::UTF8));
241 return METADATA_EDITOR_ERROR_NONE;
244 static int __ID3_getNumberOfPictures(metadata_editor_s* _metadata, TagLib::ID3v2::Tag* tag2, char** value)
246 int ret = METADATA_EDITOR_ERROR_NONE;
248 ret = __check_metadata_get_parameter(_metadata, value);
249 metadata_editor_retvm_if(ret != METADATA_EDITOR_ERROR_NONE, ret, "fail to __check_metadata_get_parameter() [%d]", ret);
250 metadata_editor_retvm_if(!tag2, METADATA_EDITOR_ERROR_OPERATION_FAILED, "Error. ID3v2 tag does not exist. Can not process further");
252 *value = g_strdup_printf("%u", tag2->frameListMap()["APIC"].size());
254 return METADATA_EDITOR_ERROR_NONE;
257 static int __ID3_getLyricsFrame(metadata_editor_s *_metadata, TagLib::ID3v2::Tag *tag2, char **value)
259 int ret = METADATA_EDITOR_ERROR_NONE;
261 ret = __check_metadata_get_parameter(_metadata, value);
262 metadata_editor_retvm_if(ret != METADATA_EDITOR_ERROR_NONE, ret, "fail to __check_metadata_get_parameter() [%d]", ret);
263 metadata_editor_retvm_if(!tag2, METADATA_EDITOR_ERROR_OPERATION_FAILED, "Error. ID3v2 tag does not exist. Can not process further");
265 TagLib::ID3v2::FrameList lst = tag2->frameListMap()["USLT"];
266 metadata_editor_retvm_if(lst.isEmpty(), METADATA_EDITOR_ERROR_NONE, "The frame USLT does not exist");
268 metadata_editor_info("The frame USLT exists");
269 TagLib::ID3v2::FrameList::Iterator it = lst.begin();
270 auto frame = static_cast<TagLib::ID3v2::UnsynchronizedLyricsFrame*>(*it);
272 *value = g_strdup(frame->text().toCString(true));
274 return METADATA_EDITOR_ERROR_NONE;
277 // *** This function is used to set text in comment frame. It processes both ID3v1 and ID3v2 tags *** //
278 // *** Comment frame is different from other string-type frames. It uses CommentsFrame instead of TextIdentificationFrame *** //
279 static int __ID3_setTwixCommentFrame(metadata_editor_s* _metadata, TagLib::ID3v1::Tag* tag1, TagLib::ID3v2::Tag* tag2, const char* value) {
280 int ret = METADATA_EDITOR_ERROR_NONE;
282 ret = __check_metadata_set_parameter(_metadata);
283 metadata_editor_retvm_if(ret != METADATA_EDITOR_ERROR_NONE, ret, "fail to __check_metadata_set_parameter() [%d]", ret);
284 metadata_editor_retvm_if(!tag2, METADATA_EDITOR_ERROR_OPERATION_FAILED, "Error. ID3v2 tag was not created. Can not proceed metadata updating");
286 // If the pointer is NULL or c-string is empty - handle as request for deletion
287 if (!value || (*value == '\0')) {
288 metadata_editor_info("Request for frame COMM deletion");
289 tag2->removeFrames("COMM");
290 if (tag1 && !tag1->isEmpty())
291 tag1->setComment("");
292 return METADATA_EDITOR_ERROR_NONE;
294 // If the comment frame is empty - create the frame and add it to the list
295 if (tag2->frameListMap()["COMM"].isEmpty()) {
296 metadata_editor_info("The frame COMM does not exist. Creating");
297 auto fr = new TagLib::ID3v2::CommentsFrame;
299 fr->setText(TagLib::String(value, TagLib::String::UTF8));
300 fr->setTextEncoding(TagLib::String::UTF8);
302 } else { // If the frame already exists - just modify its value
303 metadata_editor_info("The frame COMM exists. Changing");
304 tag2->frameListMap()["COMM"][0]->setText(TagLib::String(value, TagLib::String::UTF8));
307 if (tag1 && !tag1->isEmpty()) { // Copy the value to ID3v1 tag comment
308 metadata_editor_info("ID3v1 tag also exists. Copying frame");
309 tag1->setComment(value);
312 return METADATA_EDITOR_ERROR_NONE;
315 // *** This function is used to set text in Lyrics frame *** //
316 // *** Lyrics frame is different from other string-type frames and uses UnsynchronizedLyricsFrame instead of TextIdentificationFrame *** //
317 static int __ID3_setLyricsFrame(metadata_editor_s* _metadata, TagLib::ID3v2::Tag* tag2, const char* value) {
318 int ret = METADATA_EDITOR_ERROR_NONE;
320 ret = __check_metadata_set_parameter(_metadata);
321 metadata_editor_retvm_if(ret != METADATA_EDITOR_ERROR_NONE, ret, "fail to __check_metadata_set_parameter() [%d]", ret);
322 metadata_editor_retvm_if(!tag2, METADATA_EDITOR_ERROR_OPERATION_FAILED, "Error. ID3v2 tag was not created. Can not proceed metadata updating");
324 TagLib::ID3v2::FrameList lst = tag2->frameListMap()["USLT"]; // link to unsynchronized lyric frames in tag
325 // If the pointer is NULL or c-string is empty - handle as request for deletion
326 if (!value || (*value == '\0')) {
327 metadata_editor_info("Request for frame USLT deletion");
328 tag2->removeFrames("USLT");
329 return METADATA_EDITOR_ERROR_NONE;
331 // Check if lyrics frames exist
333 // No lyrics - create the frame and add it to the ID3v2 tag
334 metadata_editor_info("The frame USLT does not exist. Creating");
335 auto frame = new TagLib::ID3v2::UnsynchronizedLyricsFrame;
337 frame->setTextEncoding(TagLib::String::UTF8);
338 frame->setText(TagLib::String(value, TagLib::String::UTF8));
339 tag2->addFrame(frame);
340 } else { // the lyrics frames exist - change the existing one
341 metadata_editor_info("USLT frames exist in file. Changing");
342 TagLib::ID3v2::FrameList::Iterator it = lst.begin();
343 auto frame = static_cast<TagLib::ID3v2::UnsynchronizedLyricsFrame*>(*it);
344 frame->setTextEncoding(TagLib::String::UTF8);
345 frame->setText(TagLib::String(value, TagLib::String::UTF8));
348 return METADATA_EDITOR_ERROR_NONE;
351 static int __MP4_getStringItem(metadata_editor_s *_metadata, const char *itemname, char **value)
353 int ret = METADATA_EDITOR_ERROR_NONE;
355 ret = __check_metadata_get_parameter(_metadata, value);
356 metadata_editor_retvm_if(ret != METADATA_EDITOR_ERROR_NONE, ret, "fail to __check_metadata_get_parameter() [%d]", ret);
357 metadata_editor_retvm_if(!itemname, METADATA_EDITOR_ERROR_INVALID_PARAMETER, "Invalid itemname");
359 auto tag = dynamic_cast<TagLib::MP4::Tag*>(_metadata->file->tag());
360 metadata_editor_retvm_if(!tag, METADATA_EDITOR_ERROR_OPERATION_FAILED, "Tag does not exist");
362 TagLib::MP4::ItemListMap& itemMap = tag->itemListMap();
363 TagLib::MP4::ItemListMap::ConstIterator it = itemMap.find(itemname);
365 if (it != itemMap.end())
366 *value = g_strdup(it->second.toStringList()[0].toCString(true));
368 metadata_editor_info("No item <%s> in file", itemname);
370 return METADATA_EDITOR_ERROR_NONE;
373 static int __MP4_getIntegerItem(metadata_editor_s *_metadata, const char *itemname, char **value)
375 int ret = METADATA_EDITOR_ERROR_NONE;
377 ret = __check_metadata_get_parameter(_metadata, value);
378 metadata_editor_retvm_if(ret != METADATA_EDITOR_ERROR_NONE, ret, "fail to __check_metadata_get_parameter() [%d]", ret);
379 metadata_editor_retvm_if(!itemname, METADATA_EDITOR_ERROR_INVALID_PARAMETER, "Invalid itemname");
381 auto tag = dynamic_cast<TagLib::MP4::Tag*>(_metadata->file->tag());
382 metadata_editor_retvm_if(!tag, METADATA_EDITOR_ERROR_OPERATION_FAILED, "Tag does not exist");
384 TagLib::MP4::ItemListMap& itemMap = tag->itemListMap();
385 TagLib::MP4::ItemListMap::ConstIterator it = itemMap.find(itemname);
387 if (it != itemMap.end())
388 *value = g_strdup_printf("%u", it->second.toInt());
390 metadata_editor_info("No item <%s> in file", itemname);
392 return METADATA_EDITOR_ERROR_NONE;
395 static int __MP4_updateStringItem(metadata_editor_s* _metadata, const char* itemname, const char* value)
397 int ret = METADATA_EDITOR_ERROR_NONE;
399 ret = __check_metadata_set_parameter(_metadata);
400 metadata_editor_retvm_if(ret != METADATA_EDITOR_ERROR_NONE, ret, "fail to __check_metadata_set_parameter() [%d]", ret);
401 metadata_editor_retvm_if(!itemname, METADATA_EDITOR_ERROR_INVALID_PARAMETER, "Invalid itemname");
403 auto tag = dynamic_cast<TagLib::MP4::Tag*>(_metadata->file->tag());
404 metadata_editor_retvm_if(!tag, METADATA_EDITOR_ERROR_OPERATION_FAILED, "Tag does not exist");
406 // Get map of items directly from tag and launch a search of specific item
407 TagLib::MP4::ItemListMap& itemMap = tag->itemListMap();
408 // Check if it is a request for deletion
409 if ((value == NULL) || value[0] == '\0') {
410 metadata_editor_info("Request for deleting of item <%s>", itemname);
411 TagLib::MP4::ItemListMap::Iterator it = itemMap.find(itemname);
412 if (it != itemMap.end())
414 return METADATA_EDITOR_ERROR_NONE;
416 metadata_editor_info("The item <%s> will be added", itemname);
417 itemMap[itemname] = TagLib::MP4::Item(TagLib::String(value, TagLib::String::UTF8));
419 return METADATA_EDITOR_ERROR_NONE;
422 static int __MP4_updateIntegerItem(metadata_editor_s* _metadata, const char* itemname, const char* value)
424 int ret = METADATA_EDITOR_ERROR_NONE;
426 ret = __check_metadata_set_parameter(_metadata);
427 metadata_editor_retvm_if(ret != METADATA_EDITOR_ERROR_NONE, ret, "fail to __check_metadata_set_parameter() [%d]", ret);
428 metadata_editor_retvm_if(!itemname, METADATA_EDITOR_ERROR_INVALID_PARAMETER, "Invalid itemname");
430 auto tag = dynamic_cast<TagLib::MP4::Tag*>(_metadata->file->tag());
431 metadata_editor_retvm_if(!tag, METADATA_EDITOR_ERROR_OPERATION_FAILED, "Tag does not exist");
433 // Get map of items directly from tag and launch a search of specific item
434 TagLib::MP4::ItemListMap& itemMap = tag->itemListMap();
435 // Check if it is a request for deletion
436 if ((value == NULL) || value[0] == '\0') {
437 metadata_editor_info("Request for deleting of item <%s>", itemname);
438 TagLib::MP4::ItemListMap::Iterator it = itemMap.find(itemname);
439 if (it != itemMap.end())
441 return METADATA_EDITOR_ERROR_NONE;
443 // Check if the value is integer string then it can be successfully converted into integer
444 if (isdigit(value[0])) {
445 metadata_editor_info("The item <%s> will be added", itemname);
446 int number = atoi(value);
447 itemMap[itemname] = TagLib::MP4::Item(number);
448 return METADATA_EDITOR_ERROR_NONE;
449 } else { // Notify that string is not a number to process
450 metadata_editor_error("Error. String does not contain a number");
451 return METADATA_EDITOR_ERROR_INVALID_PARAMETER;
455 static int __MP4_getNumberOfPictures(metadata_editor_s* _metadata, char** value)
457 int ret = METADATA_EDITOR_ERROR_NONE;
459 ret = __check_metadata_get_parameter(_metadata, value);
460 metadata_editor_retvm_if(ret != METADATA_EDITOR_ERROR_NONE, ret, "fail to __check_metadata_get_parameter() [%d]", ret);
462 auto tag = dynamic_cast<TagLib::MP4::Tag*>(_metadata->file->tag());
463 metadata_editor_retvm_if(!tag, METADATA_EDITOR_ERROR_OPERATION_FAILED, "Tag does not exist");
465 *value = g_strdup_printf("%u", tag->contains("covr") ? tag->item("covr").toCoverArtList().size() : 0);
467 return METADATA_EDITOR_ERROR_NONE;
471 static int __xiph_getFieldValue(metadata_editor_s *_metadata, TagLib::Ogg::XiphComment *xtag, const char *fieldname, char **value)
473 int ret = METADATA_EDITOR_ERROR_NONE;
475 ret = __check_metadata_get_parameter(_metadata, value);
476 metadata_editor_retvm_if(ret != METADATA_EDITOR_ERROR_NONE, ret, "fail to __check_metadata_get_parameter() [%d]", ret);
477 metadata_editor_retvm_if(!fieldname, METADATA_EDITOR_ERROR_INVALID_PARAMETER, "Invalid fieldname");
478 metadata_editor_retvm_if(!xtag, METADATA_EDITOR_ERROR_OPERATION_FAILED, "Tag does not exist");
480 const TagLib::Ogg::FieldListMap& fieldMap = xtag->fieldListMap();
481 TagLib::Ogg::FieldListMap::ConstIterator it = fieldMap.find(fieldname);
483 if ((xtag->contains(fieldname)) && (it != fieldMap.end()))
484 *value = g_strdup(it->second[0].toCString(true));
486 metadata_editor_info("No field %s in Xiph Comment", fieldname);
488 return METADATA_EDITOR_ERROR_NONE;
491 // *** This function is used to write string into Xiph Comment fields *** //
492 static int __xiph_updateFieldValue(metadata_editor_s* _metadata, TagLib::Ogg::XiphComment* xtag, const char* fieldname, const char* value) {
493 int ret = METADATA_EDITOR_ERROR_NONE;
495 ret = __check_metadata_set_parameter(_metadata);
496 metadata_editor_retvm_if(ret != METADATA_EDITOR_ERROR_NONE, ret, "fail to __check_metadata_set_parameter() [%d]", ret);
497 metadata_editor_retvm_if(!fieldname, METADATA_EDITOR_ERROR_INVALID_PARAMETER, "Invalid fieldname");
498 metadata_editor_retvm_if(!xtag, METADATA_EDITOR_ERROR_OPERATION_FAILED, "Tag does not exist");
500 // Check if it is a request for deletion
501 if ((value == NULL) || value[0] == '\0') {
502 metadata_editor_info("Request for deleting of field %s", fieldname);
503 xtag->removeField(fieldname);
504 return METADATA_EDITOR_ERROR_NONE;
506 metadata_editor_info("The field %s will be added", fieldname);
507 // "true" is used to remove other strings of the same "fieldname" first
508 xtag->addField(fieldname, TagLib::String(value, TagLib::String::UTF8), true);
509 return METADATA_EDITOR_ERROR_NONE;
512 static int __FLAC_getNumberOfPictures(metadata_editor_s* _metadata, char** value)
514 int ret = METADATA_EDITOR_ERROR_NONE;
516 ret = __check_metadata_get_parameter(_metadata, value);
517 metadata_editor_retvm_if(ret != METADATA_EDITOR_ERROR_NONE, ret, "fail to __check_metadata_get_parameter() [%d]", ret);
519 TagLib::FLAC::File* _file = (TagLib::FLAC::File*) _metadata->file;
521 *value = g_strdup_printf("%u", _file->pictureList().size());
523 return METADATA_EDITOR_ERROR_NONE;
526 int __metadata_editor_get_file_ext(const char *file_path, char *file_ext, int max_len) {
528 unsigned int path_len = strlen(file_path);
530 for (i = (int)path_len; i >= 0; i--) {
531 if ((file_path[i] == '.') && (i < (int)path_len)) {
532 strncpy(file_ext, &file_path[i + 1], max_len);
536 /* meet the dir. no ext */
537 if (file_path[i] == '/')
544 int __metadata_editor_get_file_type(const char *path) {
546 char mimetype[255] = {0, };
548 /* get content type and mime type from file. */
549 ret = aul_get_mime_from_file(path, mimetype, sizeof(mimetype));
551 metadata_editor_debug("aul_get_mime_from_file fail.. Now trying to get type by extension");
553 char ext[255] = { 0 };
554 int ret = __metadata_editor_get_file_ext(path, ext, sizeof(ext));
555 metadata_editor_retvm_if(ret < 0, METADATA_EDITOR_FORMAT_NOTYPE, "__metadata_editor_get_file_ext failed");
557 if (strcasecmp(ext, "MP3") == 0)
558 return METADATA_EDITOR_FORMAT_MP3;
559 else if (strcasecmp(ext, "MP4") == 0)
560 return METADATA_EDITOR_FORMAT_MP4;
562 return METADATA_EDITOR_FORMAT_NOTYPE;
565 metadata_editor_debug("mime type : %s", mimetype);
567 /* categorize from mimetype */
568 if (strstr(mimetype, "mpeg") != NULL)
569 return METADATA_EDITOR_FORMAT_MP3;
570 else if (strstr(mimetype, "mp4") != NULL)
571 return METADATA_EDITOR_FORMAT_MP4;
573 return METADATA_EDITOR_FORMAT_NOTYPE;
576 static int __metadata_editor_get_picture_type(const char *path, char **type) {
578 char mimetype[255] = {0, };
580 /* get content type and mime type from file. */
581 ret = aul_get_mime_from_file(path, mimetype, sizeof(mimetype));
583 metadata_editor_debug("aul_get_mime_from_file fail.. Now trying to get type by extension");
585 char ext[255] = { 0 };
586 int ret = __metadata_editor_get_file_ext(path, ext, sizeof(ext));
587 metadata_editor_retvm_if(ret < 0, METADATA_EDITOR_ERROR_OPERATION_FAILED, "__metadata_editor_get_file_ext failed");
589 if (strcasecmp(ext, "JPG") == 0 || strcasecmp(ext, "JPEG") == 0) {
590 *type = g_strdup(MIME_TYPE_JPEG);
591 return METADATA_EDITOR_ERROR_NONE;
592 } else if (strcasecmp(ext, "PNG") == 0) {
593 *type = g_strdup(MIME_TYPE_JPEG);
594 return METADATA_EDITOR_ERROR_NONE;
596 return METADATA_EDITOR_ERROR_NOT_SUPPORTED;
600 metadata_editor_debug("mime type : %s", mimetype);
602 /* categorize from mimetype */
603 if (strstr(mimetype, "jpeg") != NULL) {
604 *type = g_strndup(mimetype, strlen(mimetype));
605 return METADATA_EDITOR_ERROR_NONE;
606 } else if (strstr(mimetype, "png") != NULL) {
607 *type = g_strndup(mimetype, strlen(mimetype));
608 return METADATA_EDITOR_ERROR_NONE;
611 return METADATA_EDITOR_ERROR_NOT_SUPPORTED;
614 int __metadata_editor_get_picture_info(const char *path, void **picture, size_t *size, char **type) {
617 ret = __metadata_editor_get_picture_type(path, type);
618 if (ret != METADATA_EDITOR_ERROR_NONE)
619 return METADATA_EDITOR_ERROR_OPERATION_FAILED;
622 FILE* fin = fopen(path, "rb");
623 size_t file_size = 0;
626 while (fgetc(fin) != EOF)
630 char picture_buffer[file_size] = {0, };
631 memset(picture_buffer, 0, file_size * sizeof(char));
632 fin = fopen(path, "rb");
634 if(file_size != fread(picture_buffer, 1, file_size, fin)) {
635 metadata_editor_error("fread error");
637 return METADATA_EDITOR_ERROR_OPERATION_FAILED;
641 if (*picture == NULL) {
642 *picture = malloc(file_size * sizeof(char));
643 memset(*picture, 0, file_size * sizeof(char));
644 memcpy(*picture, picture_buffer, file_size);
649 return METADATA_EDITOR_ERROR_NONE;
652 // *** This function is used to allocate the metadata_editor_s in memory *** //
653 // *** The structure metadata_editor_s contains all information about the file *** //
654 extern "C" int metadata_editor_create(metadata_editor_h *metadata) {
655 metadata_editor_retvm_if(metadata == NULL, METADATA_EDITOR_ERROR_INVALID_PARAMETER, "Invalid metadata");
657 metadata_editor_s *_metadata = g_new0(metadata_editor_s, 1);
659 _metadata->file = NULL;
660 _metadata->filetype = METADATA_EDITOR_FORMAT_NOTYPE; // Specify file type out of range
662 // Save the structure in the metadata
663 *metadata = (metadata_editor_h)_metadata;
665 return METADATA_EDITOR_ERROR_NONE;
668 // *** This function is used to open the file. It creates the instance that is responsible for connection with file *** //
669 extern "C" int metadata_editor_set_path(metadata_editor_h metadata, const char *path) {
670 int media_type = METADATA_EDITOR_FORMAT_NOTYPE;
671 metadata_editor_s *_metadata = (metadata_editor_s*)metadata;
672 TagLib::File* _file = NULL;
674 metadata_editor_retvm_if(!_metadata, METADATA_EDITOR_ERROR_INVALID_PARAMETER, "Invalid metadata");
675 metadata_editor_retvm_if(!path, METADATA_EDITOR_ERROR_INVALID_PARAMETER, "Invalid path");
677 if (access(path, R_OK) < 0) {
678 if (errno == EACCES || errno == EPERM) {
679 metadata_editor_error("Permission denied");
680 return METADATA_EDITOR_ERROR_PERMISSION_DENIED;
682 metadata_editor_error("Fail to open path");
683 return METADATA_EDITOR_ERROR_FILE_EXISTS;
687 media_type = __metadata_editor_get_file_type(path);
689 if (_metadata->file) {
690 metadata_editor_info("file free [%p]", _metadata->file);
691 delete _metadata->file;
693 _metadata->file = NULL;
694 _metadata->filetype = METADATA_EDITOR_FORMAT_NOTYPE;
698 switch (media_type) {
699 case METADATA_EDITOR_FORMAT_MP3:
700 _file = new TagLib::MPEG::File(path);
703 case METADATA_EDITOR_FORMAT_MP4:
704 _file = new TagLib::MP4::File(path);
708 case METADATA_EDITOR_FORMAT_FLAC:
709 _file = new TagLib::FLAC::File(path);
712 case METADATA_EDITOR_FORMAT_OGG_VORBIS:
713 _file = new TagLib::Ogg::Vorbis::File(path);
716 case METADATA_EDITOR_FORMAT_OGG_FLAC:
717 _file = new TagLib::Ogg::FLAC::File(path);
720 case METADATA_EDITOR_FORMAT_WAV:
721 // Allocate the file object in memory to work with it later on
722 _file = new TagLib::RIFF::WAV::File(path);
727 metadata_editor_error("Wrong file type");
728 return METADATA_EDITOR_ERROR_NOT_SUPPORTED;
730 } catch (const std::bad_alloc &ex) {
731 metadata_editor_retvm_if(!_file, METADATA_EDITOR_ERROR_OUT_OF_MEMORY, "OUT_OF_MEMORY");
734 if (!_file->isOpen()) {
735 metadata_editor_error("The file was not found. Pointer address is %p", _file);
737 return METADATA_EDITOR_ERROR_PERMISSION_DENIED;
740 _metadata->file = _file;
741 _metadata->filetype = media_type;
743 return METADATA_EDITOR_ERROR_NONE;
746 static int __metadata_editor_get_mp3_metadata(metadata_editor_s *metadata, metadata_editor_attr_e attribute, char **value)
748 int ret = METADATA_EDITOR_ERROR_NONE;
750 ret = __check_metadata_get_parameter(metadata, value);
751 metadata_editor_retvm_if(ret != METADATA_EDITOR_ERROR_NONE, ret, "fail to __check_metadata_get_parameter() [%d]", ret);
753 // Bring the pointer to actual file type and make tag pointers
754 TagLib::MPEG::File* _file = (TagLib::MPEG::File*)metadata->file;
755 TagLib::ID3v1::Tag* tag1 = _file->ID3v1Tag();
756 TagLib::ID3v2::Tag* tag2 = _file->ID3v2Tag();
758 switch (attribute) { // Check which one of frame types was given to the function for processing
759 case METADATA_EDITOR_ATTR_ARTIST: return __ID3_getTwixFrameByName(metadata, tag1, tag2, "TPE1", value);
760 case METADATA_EDITOR_ATTR_TITLE: return __ID3_getTwixFrameByName(metadata, tag1, tag2, "TIT2", value);
761 case METADATA_EDITOR_ATTR_ALBUM: return __ID3_getTwixFrameByName(metadata, tag1, tag2, "TALB", value);
762 case METADATA_EDITOR_ATTR_GENRE: return __ID3_getTwixFrameByName(metadata, tag1, tag2, "TCON", value);
763 case METADATA_EDITOR_ATTR_AUTHOR: return __ID3_getFrameByName(metadata, tag2, "TCOM", value);
764 case METADATA_EDITOR_ATTR_COPYRIGHT: return __ID3_getFrameByName(metadata, tag2, "TCOP", value);
765 case METADATA_EDITOR_ATTR_DATE: return __ID3_getTwixFrameByName(metadata, tag1, tag2, "TDRC", value);
766 case METADATA_EDITOR_ATTR_DESCRIPTION: return __ID3_getFrameByName(metadata, tag2, "TIT3", value);
767 case METADATA_EDITOR_ATTR_COMMENT: return __ID3_getTwixFrameByName(metadata, tag1, tag2, "COMM", value);
768 case METADATA_EDITOR_ATTR_TRACK_NUM: return __ID3_getTwixFrameByName(metadata, tag1, tag2, "TRCK", value);
769 case METADATA_EDITOR_ATTR_CONDUCTOR: return __ID3_getFrameByName(metadata, tag2, "TPE3", value);
770 case METADATA_EDITOR_ATTR_PICTURE_NUM: return __ID3_getNumberOfPictures(metadata, tag2, value);
771 case METADATA_EDITOR_ATTR_UNSYNCLYRICS: return __ID3_getLyricsFrame(metadata, tag2, value);
773 return METADATA_EDITOR_ERROR_INVALID_PARAMETER;
777 static int __metadata_editor_get_mp4_metadata(metadata_editor_s *metadata, metadata_editor_attr_e attribute, char **value)
779 int ret = METADATA_EDITOR_ERROR_NONE;
781 ret = __check_metadata_get_parameter(metadata, value);
782 metadata_editor_retvm_if(ret != METADATA_EDITOR_ERROR_NONE, ret, "fail to __check_metadata_get_parameter() [%d]", ret);
784 switch (attribute) { // Check which one of frame types was given to the function for processing
785 case METADATA_EDITOR_ATTR_ARTIST: return __MP4_getStringItem(metadata, "\xA9""ART", value);
786 case METADATA_EDITOR_ATTR_TITLE: return __MP4_getStringItem(metadata, "\xA9""nam", value);
787 case METADATA_EDITOR_ATTR_ALBUM: return __MP4_getStringItem(metadata, "\xA9""alb", value);
788 case METADATA_EDITOR_ATTR_GENRE: return __MP4_getStringItem(metadata, "\xA9""gen", value);
789 case METADATA_EDITOR_ATTR_AUTHOR: return __MP4_getStringItem(metadata, "\xA9""wrt", value);
790 case METADATA_EDITOR_ATTR_COPYRIGHT: return __MP4_getStringItem(metadata, "cprt", value);
791 case METADATA_EDITOR_ATTR_DATE: return __MP4_getStringItem(metadata, "\xA9""day", value);
792 case METADATA_EDITOR_ATTR_DESCRIPTION: return __MP4_getStringItem(metadata, "desc", value);
793 case METADATA_EDITOR_ATTR_COMMENT: return __MP4_getStringItem(metadata, "\xA9""cmt", value);
794 case METADATA_EDITOR_ATTR_TRACK_NUM: return __MP4_getIntegerItem(metadata, "trkn", value);
795 case METADATA_EDITOR_ATTR_CONDUCTOR: return __MP4_getStringItem(metadata, "cond", value);
796 case METADATA_EDITOR_ATTR_UNSYNCLYRICS: return __MP4_getStringItem(metadata, "\xA9""lyr", value);
797 case METADATA_EDITOR_ATTR_PICTURE_NUM: return __MP4_getNumberOfPictures(metadata, value);
799 return METADATA_EDITOR_ERROR_INVALID_PARAMETER;
804 static int __metadata_editor_get_flac_metadata(metadata_editor_s *metadata, metadata_editor_attr_e attribute, char **value)
806 int ret = METADATA_EDITOR_ERROR_NONE;
808 ret = __check_metadata_get_parameter(metadata, value);
809 metadata_editor_retvm_if(ret != METADATA_EDITOR_ERROR_NONE, ret, "fail to __check_metadata_get_parameter() [%d]", ret);
811 // Bring the pointer to actual file type and make tags pointers
812 TagLib::FLAC::File* _file = (TagLib::FLAC::File*)metadata->file;
813 TagLib::Ogg::XiphComment* xtag = _file->xiphComment(false);
814 if (!xtag) { // Check if we have a valid tag for processing
815 metadata_editor_error("Tag does not exist");
817 return METADATA_EDITOR_ERROR_OPERATION_FAILED;
819 switch (attribute) { // Check which one of frame types was given to the function for processing
820 case METADATA_EDITOR_ATTR_ARTIST: return __xiph_getFieldValue(metadata, xtag, "ARTIST", value);
821 case METADATA_EDITOR_ATTR_TITLE: return __xiph_getFieldValue(metadata, xtag, "TITLE", value);
822 case METADATA_EDITOR_ATTR_ALBUM: return __xiph_getFieldValue(metadata, xtag, "ALBUM", value);
823 case METADATA_EDITOR_ATTR_GENRE: return __xiph_getFieldValue(metadata, xtag, "GENRE", value);
824 case METADATA_EDITOR_ATTR_AUTHOR: return __xiph_getFieldValue(metadata, xtag, "COMPOSER", value);
825 case METADATA_EDITOR_ATTR_COPYRIGHT: return __xiph_getFieldValue(metadata, xtag, "COPYRIGHT", value);
826 case METADATA_EDITOR_ATTR_DATE: return __xiph_getFieldValue(metadata, xtag, "DATE", value);
827 case METADATA_EDITOR_ATTR_DESCRIPTION: return __xiph_getFieldValue(metadata, xtag, "DESCRIPTION", value);
828 case METADATA_EDITOR_ATTR_COMMENT: return __xiph_getFieldValue(metadata, xtag, "COMMENT", value);
829 case METADATA_EDITOR_ATTR_TRACK_NUM: return __xiph_getFieldValue(metadata, xtag, "TRACKNUMBER", value);
830 case METADATA_EDITOR_ATTR_CONDUCTOR: return __xiph_getFieldValue(metadata, xtag, "CONDUCTOR", value);
831 case METADATA_EDITOR_ATTR_UNSYNCLYRICS: return __xiph_getFieldValue(metadata, xtag, "LYRICS", value);
832 case METADATA_EDITOR_ATTR_PICTURE_NUM: return __FLAC_getNumberOfPictures(metadata, value);
834 return METADATA_EDITOR_ERROR_INVALID_PARAMETER;
838 static int __metadata_editor_get_ogg_vorbis_metadata(metadata_editor_s *metadata, metadata_editor_attr_e attribute, char **value)
840 int ret = METADATA_EDITOR_ERROR_NONE;
842 ret = __check_metadata_get_parameter(metadata, value);
843 metadata_editor_retvm_if(ret != METADATA_EDITOR_ERROR_NONE, ret, "fail to __check_metadata_get_parameter() [%d]", ret);
845 // Bring the pointer to actual file type and make tags pointers
846 TagLib::Ogg::Vorbis::File* _file = (TagLib::Ogg::Vorbis::File*)metadata->file;
847 TagLib::Ogg::XiphComment* xtag = _file->tag();
848 if (!xtag) { // Check if we have a valid tag for processing
849 metadata_editor_error("Tag does not exist");
851 return METADATA_EDITOR_ERROR_OPERATION_FAILED;
853 switch (attribute) { // Check which one of frame types was given to the function for processing
854 case METADATA_EDITOR_ATTR_ARTIST: return __xiph_getFieldValue(metadata, xtag, "ARTIST", value);
855 case METADATA_EDITOR_ATTR_TITLE: return __xiph_getFieldValue(metadata, xtag, "TITLE", value);
856 case METADATA_EDITOR_ATTR_ALBUM: return __xiph_getFieldValue(metadata, xtag, "ALBUM", value);
857 case METADATA_EDITOR_ATTR_GENRE: return __xiph_getFieldValue(metadata, xtag, "GENRE", value);
858 case METADATA_EDITOR_ATTR_AUTHOR: return __xiph_getFieldValue(metadata, xtag, "COMPOSER", value);
859 case METADATA_EDITOR_ATTR_COPYRIGHT: return __xiph_getFieldValue(metadata, xtag, "COPYRIGHT", value);
860 case METADATA_EDITOR_ATTR_DATE: return __xiph_getFieldValue(metadata, xtag, "DATE", value);
861 case METADATA_EDITOR_ATTR_DESCRIPTION: return __xiph_getFieldValue(metadata, xtag, "DESCRIPTION", value);
862 case METADATA_EDITOR_ATTR_COMMENT: return __xiph_getFieldValue(metadata, xtag, "COMMENT", value);
863 case METADATA_EDITOR_ATTR_TRACK_NUM: return __xiph_getFieldValue(metadata, xtag, "TRACKNUMBER", value);
864 case METADATA_EDITOR_ATTR_CONDUCTOR: return __xiph_getFieldValue(metadata, xtag, "CONDUCTOR", value);
865 case METADATA_EDITOR_ATTR_UNSYNCLYRICS: return __xiph_getFieldValue(metadata, xtag, "LYRICS", value);
867 return METADATA_EDITOR_ERROR_INVALID_PARAMETER;
871 static int __metadata_editor_get_ogg_flac_metadata(metadata_editor_s *metadata, metadata_editor_attr_e attribute, char **value)
873 int ret = METADATA_EDITOR_ERROR_NONE;
875 ret = __check_metadata_get_parameter(metadata, value);
876 metadata_editor_retvm_if(ret != METADATA_EDITOR_ERROR_NONE, ret, "fail to __check_metadata_get_parameter() [%d]", ret);
878 // Bring the pointer to actual file type and make tags pointers
879 TagLib::Ogg::FLAC::File* _file = (TagLib::Ogg::FLAC::File*)metadata->file;
880 TagLib::Ogg::XiphComment* xtag = _file->tag();
881 if (!xtag) { // Check if we have a valid tag for processing
882 metadata_editor_error("Tag does not exist");
884 return METADATA_EDITOR_ERROR_OPERATION_FAILED;
886 switch (attribute) { // Check which one of frame types was given to the function for processing
887 case METADATA_EDITOR_ATTR_ARTIST: return __xiph_getFieldValue(metadata, xtag, "ARTIST", value);
888 case METADATA_EDITOR_ATTR_TITLE: return __xiph_getFieldValue(metadata, xtag, "TITLE", value);
889 case METADATA_EDITOR_ATTR_ALBUM: return __xiph_getFieldValue(metadata, xtag, "ALBUM", value);
890 case METADATA_EDITOR_ATTR_GENRE: return __xiph_getFieldValue(metadata, xtag, "GENRE", value);
891 case METADATA_EDITOR_ATTR_AUTHOR: return __xiph_getFieldValue(metadata, xtag, "COMPOSER", value);
892 case METADATA_EDITOR_ATTR_COPYRIGHT: return __xiph_getFieldValue(metadata, xtag, "COPYRIGHT", value);
893 case METADATA_EDITOR_ATTR_DATE: return __xiph_getFieldValue(metadata, xtag, "DATE", value);
894 case METADATA_EDITOR_ATTR_DESCRIPTION: return __xiph_getFieldValue(metadata, xtag, "DESCRIPTION", value);
895 case METADATA_EDITOR_ATTR_COMMENT: return __xiph_getFieldValue(metadata, xtag, "COMMENT", value);
896 case METADATA_EDITOR_ATTR_TRACK_NUM: return __xiph_getFieldValue(metadata, xtag, "TRACKNUMBER", value);
897 case METADATA_EDITOR_ATTR_CONDUCTOR: return __xiph_getFieldValue(metadata, xtag, "CONDUCTOR", value);
898 case METADATA_EDITOR_ATTR_UNSYNCLYRICS: return __xiph_getFieldValue(metadata, xtag, "LYRICS", value);
900 return METADATA_EDITOR_ERROR_INVALID_PARAMETER;
904 static int __metadata_editor_get_wav_metadata(metadata_editor_s *metadata, metadata_editor_attr_e attribute, char **value)
906 int ret = METADATA_EDITOR_ERROR_NONE;
908 ret = __check_metadata_get_parameter(metadata, value);
909 metadata_editor_retvm_if(ret != METADATA_EDITOR_ERROR_NONE, ret, "fail to __check_metadata_get_parameter() [%d]", ret);
911 // Bring the pointer to actual file type and make tag pointers
912 TagLib::RIFF::WAV::File* _file = (TagLib::RIFF::WAV::File*)metadata->file;
913 TagLib::ID3v2::Tag* tag2 = _file->tag();
915 if (tag2 == NULL) { // Check if we have a valid tag for processing
916 metadata_editor_error("Error. ID3v2 tag does not exist. Can not proceed metadata extraction");
918 return METADATA_EDITOR_ERROR_OPERATION_FAILED;
921 switch (attribute) { // Check which one of frame types was given to the function for processing
922 case METADATA_EDITOR_ATTR_ARTIST: return __ID3_getFrameByName(metadata, tag2, "TPE1", value);
923 case METADATA_EDITOR_ATTR_TITLE: return __ID3_getFrameByName(metadata, tag2, "TIT2", value);
924 case METADATA_EDITOR_ATTR_ALBUM: return __ID3_getFrameByName(metadata, tag2, "TALB", value);
925 case METADATA_EDITOR_ATTR_GENRE: return __ID3_getFrameByName(metadata, tag2, "TCON", value);
926 case METADATA_EDITOR_ATTR_AUTHOR: return __ID3_getFrameByName(metadata, tag2, "TCOM", value);
927 case METADATA_EDITOR_ATTR_COPYRIGHT: return __ID3_getFrameByName(metadata, tag2, "TCOP", value);
928 case METADATA_EDITOR_ATTR_DATE: return __ID3_getFrameByName(metadata, tag2, "TDRC", value);
929 case METADATA_EDITOR_ATTR_DESCRIPTION: return __ID3_getFrameByName(metadata, tag2, "TIT3", value);
930 case METADATA_EDITOR_ATTR_COMMENT: return __ID3_getFrameByName(metadata, tag2, "COMM", value);
931 case METADATA_EDITOR_ATTR_TRACK_NUM: return __ID3_getFrameByName(metadata, tag2, "TRCK", value);
932 case METADATA_EDITOR_ATTR_CONDUCTOR: return __ID3_getFrameByName(metadata, tag2, "TPE3", value);
933 case METADATA_EDITOR_ATTR_PICTURE_NUM: return __ID3_getNumberOfPictures(metadata, tag2, value);
934 case METADATA_EDITOR_ATTR_UNSYNCLYRICS: return __ID3_getLyricsFrame(metadata, tag2, value);
936 return METADATA_EDITOR_ERROR_INVALID_PARAMETER;
941 // *** This function is used to get the tag frame (field, item - each tag has its own name for data unit) from file *** //
942 extern "C" int metadata_editor_get_metadata(metadata_editor_h metadata, metadata_editor_attr_e attribute, char **value) {
944 metadata_editor_s *_metadata = (metadata_editor_s*)metadata;
945 metadata_editor_retvm_if(!_metadata, METADATA_EDITOR_ERROR_INVALID_PARAMETER, "Invalid metadata");
947 switch (_metadata->filetype) {
948 case METADATA_EDITOR_FORMAT_MP3:
949 return __metadata_editor_get_mp3_metadata(_metadata, attribute, value);
951 case METADATA_EDITOR_FORMAT_MP4:
952 return __metadata_editor_get_mp4_metadata(_metadata, attribute, value);
955 case METADATA_EDITOR_FORMAT_FLAC:
956 return __metadata_editor_get_flac_metadata(_metadata, attribute, value);
958 case METADATA_EDITOR_FORMAT_OGG_VORBIS:
959 return __metadata_editor_get_ogg_vorbis_metadata(_metadata, attribute, value);
961 case METADATA_EDITOR_FORMAT_OGG_FLAC:
962 return __metadata_editor_get_ogg_flac_metadata(_metadata, attribute, value);
964 case METADATA_EDITOR_FORMAT_WAV:
965 return __metadata_editor_get_wav_metadata(_metadata, attribute, value);
969 metadata_editor_error("Wrong file type [%d]", _metadata->filetype);
970 return METADATA_EDITOR_ERROR_INVALID_PARAMETER;
974 static int __metadata_editor_set_mp3_metadata(metadata_editor_s* metadata, metadata_editor_attr_e attribute, const char* value)
976 int ret = METADATA_EDITOR_ERROR_NONE;
978 ret = __check_metadata_set_parameter(metadata);
979 metadata_editor_retvm_if(ret != METADATA_EDITOR_ERROR_NONE, ret, "fail to __check_metadata_set_parameter() [%d]", ret);
981 // Bring the pointer to actual file type and make tags pointers
982 TagLib::MPEG::File* _file = (TagLib::MPEG::File*)metadata->file;
983 TagLib::ID3v1::Tag* tag1 = _file->ID3v1Tag();
984 TagLib::ID3v2::Tag* tag2 = _file->ID3v2Tag(true);
986 metadata_editor_retvm_if(tag2 == NULL, METADATA_EDITOR_ERROR_OPERATION_FAILED, "Error. ID3v2 tag was not created. Can not proceed metadata updating");
988 switch (attribute) { // Check which one of frame type was given for processing
989 case METADATA_EDITOR_ATTR_ARTIST: return __ID3_setTwixFrameByName(metadata, tag1, tag2, "TPE1", value);
990 case METADATA_EDITOR_ATTR_TITLE: return __ID3_setTwixFrameByName(metadata, tag1, tag2, "TIT2", value);
991 case METADATA_EDITOR_ATTR_ALBUM: return __ID3_setTwixFrameByName(metadata, tag1, tag2, "TALB", value);
992 case METADATA_EDITOR_ATTR_GENRE: return __ID3_setTwixFrameByName(metadata, tag1, tag2, "TCON", value);
993 case METADATA_EDITOR_ATTR_AUTHOR: return __ID3_setFrameByName(metadata, tag2, "TCOM", value);
994 case METADATA_EDITOR_ATTR_COPYRIGHT: return __ID3_setFrameByName(metadata, tag2, "TCOP", value);
995 case METADATA_EDITOR_ATTR_DATE: return __ID3_setTwixFrameByName(metadata, tag1, tag2, "TDRC", value);
996 case METADATA_EDITOR_ATTR_DESCRIPTION: return __ID3_setFrameByName(metadata, tag2, "TIT3", value);
997 case METADATA_EDITOR_ATTR_TRACK_NUM: return __ID3_setTwixFrameByName(metadata, tag1, tag2, "TRCK", value);
998 case METADATA_EDITOR_ATTR_CONDUCTOR: return __ID3_setFrameByName(metadata, tag2, "TPE3", value);
999 case METADATA_EDITOR_ATTR_COMMENT: return __ID3_setTwixCommentFrame(metadata, tag1, tag2, value);
1000 case METADATA_EDITOR_ATTR_UNSYNCLYRICS: return __ID3_setLyricsFrame(metadata, tag2, value);
1002 return METADATA_EDITOR_ERROR_INVALID_PARAMETER;
1006 static int __metadata_editor_set_mp4_metadata(metadata_editor_s* metadata, metadata_editor_attr_e attribute, const char* value)
1008 int ret = METADATA_EDITOR_ERROR_NONE;
1010 ret = __check_metadata_set_parameter(metadata);
1011 metadata_editor_retvm_if(ret != METADATA_EDITOR_ERROR_NONE, ret, "fail to __check_metadata_set_parameter() [%d]", ret);
1013 switch (attribute) { // Check which one of frame type was given for processing
1014 case METADATA_EDITOR_ATTR_ARTIST: return __MP4_updateStringItem(metadata, "\xA9""ART", value);
1015 case METADATA_EDITOR_ATTR_TITLE: return __MP4_updateStringItem(metadata, "\xA9""nam", value);
1016 case METADATA_EDITOR_ATTR_ALBUM: return __MP4_updateStringItem(metadata, "\xA9""alb", value);
1017 case METADATA_EDITOR_ATTR_GENRE: return __MP4_updateStringItem(metadata, "\xA9""gen", value);
1018 case METADATA_EDITOR_ATTR_AUTHOR: return __MP4_updateStringItem(metadata, "\xA9""wrt", value);
1019 case METADATA_EDITOR_ATTR_COPYRIGHT: return __MP4_updateStringItem(metadata, "cprt", value);
1020 case METADATA_EDITOR_ATTR_DATE: return __MP4_updateStringItem(metadata, "\xA9""day", value);
1021 case METADATA_EDITOR_ATTR_DESCRIPTION: return __MP4_updateStringItem(metadata, "desc", value);
1022 case METADATA_EDITOR_ATTR_COMMENT: return __MP4_updateStringItem(metadata, "\xA9""cmt", value);
1023 case METADATA_EDITOR_ATTR_TRACK_NUM: return __MP4_updateIntegerItem(metadata, "trkn", value);
1024 case METADATA_EDITOR_ATTR_CONDUCTOR: return __MP4_updateStringItem(metadata, "cond", value);
1025 case METADATA_EDITOR_ATTR_UNSYNCLYRICS: return __MP4_updateStringItem(metadata, "\xA9""lyr", value);
1027 return METADATA_EDITOR_ERROR_INVALID_PARAMETER;
1032 static int __metadata_editor_set_flac_metadata(metadata_editor_s* metadata, metadata_editor_attr_e attribute, const char* value)
1034 int ret = METADATA_EDITOR_ERROR_NONE;
1036 ret = __check_metadata_set_parameter(metadata);
1037 metadata_editor_retvm_if(ret != METADATA_EDITOR_ERROR_NONE, ret, "fail to __check_metadata_set_parameter() [%d]", ret);
1039 // Bring the pointer to actual file type and make tags pointers
1040 TagLib::FLAC::File* _file = (TagLib::FLAC::File*)metadata->file;
1041 TagLib::Ogg::XiphComment* xtag = _file->xiphComment(true);
1042 if (!xtag) { // Check if we have a valid tag for processing
1043 metadata_editor_error("Error. Xiph Comment was not created. Can not proceed metadata updating");
1044 return METADATA_EDITOR_ERROR_OPERATION_FAILED;
1046 switch (attribute) { // Check which one of frame type was given for processing
1047 case METADATA_EDITOR_ATTR_ARTIST: return __xiph_updateFieldValue(metadata, xtag, "ARTIST", value);
1048 case METADATA_EDITOR_ATTR_TITLE: return __xiph_updateFieldValue(metadata, xtag, "TITLE", value);
1049 case METADATA_EDITOR_ATTR_ALBUM: return __xiph_updateFieldValue(metadata, xtag, "ALBUM", value);
1050 case METADATA_EDITOR_ATTR_GENRE: return __xiph_updateFieldValue(metadata, xtag, "GENRE", value);
1051 case METADATA_EDITOR_ATTR_AUTHOR: return __xiph_updateFieldValue(metadata, xtag, "COMPOSER", value);
1052 case METADATA_EDITOR_ATTR_COPYRIGHT: return __xiph_updateFieldValue(metadata, xtag, "COPYRIGHT", value);
1053 case METADATA_EDITOR_ATTR_DATE: return __xiph_updateFieldValue(metadata, xtag, "DATE", value);
1054 case METADATA_EDITOR_ATTR_DESCRIPTION: return __xiph_updateFieldValue(metadata, xtag, "DESCRIPTION", value);
1055 case METADATA_EDITOR_ATTR_COMMENT: return __xiph_updateFieldValue(metadata, xtag, "COMMENT", value);
1056 case METADATA_EDITOR_ATTR_TRACK_NUM: return __xiph_updateFieldValue(metadata, xtag, "TRACKNUMBER", value);
1057 case METADATA_EDITOR_ATTR_CONDUCTOR: return __xiph_updateFieldValue(metadata, xtag, "CONDUCTOR", value);
1058 case METADATA_EDITOR_ATTR_UNSYNCLYRICS: return __xiph_updateFieldValue(metadata, xtag, "LYRICS", value);
1060 return METADATA_EDITOR_ERROR_INVALID_PARAMETER;
1064 static int __metadata_editor_set_ogg_vorbis_metadata(metadata_editor_s* metadata, metadata_editor_attr_e attribute, const char* value)
1066 int ret = METADATA_EDITOR_ERROR_NONE;
1068 ret = __check_metadata_set_parameter(metadata);
1069 metadata_editor_retvm_if(ret != METADATA_EDITOR_ERROR_NONE, ret, "fail to __check_metadata_set_parameter() [%d]", ret);
1071 // Bring the pointer to actual file type and make tags pointers
1072 TagLib::Ogg::Vorbis::File* _file = (TagLib::Ogg::Vorbis::File*)metadata->file;
1073 TagLib::Ogg::XiphComment* xtag = _file->tag();
1074 if (!xtag) { // Check if we have a valid tag for processing
1075 metadata_editor_error("Error. Xiph Comment was not created. Can not proceed metadata updating");
1076 return METADATA_EDITOR_ERROR_OPERATION_FAILED;
1078 switch (attribute) { // Check which one of frame type was given for processing
1079 case METADATA_EDITOR_ATTR_ARTIST: return __xiph_updateFieldValue(metadata, xtag, "ARTIST", value);
1080 case METADATA_EDITOR_ATTR_TITLE: return __xiph_updateFieldValue(metadata, xtag, "TITLE", value);
1081 case METADATA_EDITOR_ATTR_ALBUM: return __xiph_updateFieldValue(metadata, xtag, "ALBUM", value);
1082 case METADATA_EDITOR_ATTR_GENRE: return __xiph_updateFieldValue(metadata, xtag, "GENRE", value);
1083 case METADATA_EDITOR_ATTR_AUTHOR: return __xiph_updateFieldValue(metadata, xtag, "COMPOSER", value);
1084 case METADATA_EDITOR_ATTR_COPYRIGHT: return __xiph_updateFieldValue(metadata, xtag, "COPYRIGHT", value);
1085 case METADATA_EDITOR_ATTR_DATE: return __xiph_updateFieldValue(metadata, xtag, "DATE", value);
1086 case METADATA_EDITOR_ATTR_DESCRIPTION: return __xiph_updateFieldValue(metadata, xtag, "DESCRIPTION", value);
1087 case METADATA_EDITOR_ATTR_COMMENT: return __xiph_updateFieldValue(metadata, xtag, "COMMENT", value);
1088 case METADATA_EDITOR_ATTR_TRACK_NUM: return __xiph_updateFieldValue(metadata, xtag, "TRACKNUMBER", value);
1089 case METADATA_EDITOR_ATTR_CONDUCTOR: return __xiph_updateFieldValue(metadata, xtag, "CONDUCTOR", value);
1090 case METADATA_EDITOR_ATTR_UNSYNCLYRICS: return __xiph_updateFieldValue(metadata, xtag, "LYRICS", value);
1092 return METADATA_EDITOR_ERROR_INVALID_PARAMETER;
1096 static int __metadata_editor_set_ogg_flac_metadata(metadata_editor_s* metadata, metadata_editor_attr_e attribute, const char* value)
1098 int ret = METADATA_EDITOR_ERROR_NONE;
1100 ret = __check_metadata_set_parameter(metadata);
1101 metadata_editor_retvm_if(ret != METADATA_EDITOR_ERROR_NONE, ret, "fail to __check_metadata_set_parameter() [%d]", ret);
1103 // Bring the pointer to actual file type and make tags pointers
1104 TagLib::Ogg::FLAC::File* _file = (TagLib::Ogg::FLAC::File*)metadata->file;
1105 TagLib::Ogg::XiphComment* xtag = _file->tag();
1106 if (!xtag) { // Check if we have a valid tag for processing
1107 metadata_editor_error("Error. Xiph Comment was not created. Can not proceed metadata updating");
1108 return METADATA_EDITOR_ERROR_OPERATION_FAILED;
1110 switch (attribute) { // Check which one of frame type was given for processing
1111 case METADATA_EDITOR_ATTR_ARTIST: return __xiph_updateFieldValue(metadata, xtag, "ARTIST", value);
1112 case METADATA_EDITOR_ATTR_TITLE: return __xiph_updateFieldValue(metadata, xtag, "TITLE", value);
1113 case METADATA_EDITOR_ATTR_ALBUM: return __xiph_updateFieldValue(metadata, xtag, "ALBUM", value);
1114 case METADATA_EDITOR_ATTR_GENRE: return __xiph_updateFieldValue(metadata, xtag, "GENRE", value);
1115 case METADATA_EDITOR_ATTR_AUTHOR: return __xiph_updateFieldValue(metadata, xtag, "COMPOSER", value);
1116 case METADATA_EDITOR_ATTR_COPYRIGHT: return __xiph_updateFieldValue(metadata, xtag, "COPYRIGHT", value);
1117 case METADATA_EDITOR_ATTR_DATE: return __xiph_updateFieldValue(metadata, xtag, "DATE", value);
1118 case METADATA_EDITOR_ATTR_DESCRIPTION: return __xiph_updateFieldValue(metadata, xtag, "DESCRIPTION", value);
1119 case METADATA_EDITOR_ATTR_COMMENT: return __xiph_updateFieldValue(metadata, xtag, "COMMENT", value);
1120 case METADATA_EDITOR_ATTR_TRACK_NUM: return __xiph_updateFieldValue(metadata, xtag, "TRACKNUMBER", value);
1121 case METADATA_EDITOR_ATTR_CONDUCTOR: return __xiph_updateFieldValue(metadata, xtag, "CONDUCTOR", value);
1122 case METADATA_EDITOR_ATTR_UNSYNCLYRICS: return __xiph_updateFieldValue(metadata, xtag, "LYRICS", value);
1124 return METADATA_EDITOR_ERROR_INVALID_PARAMETER;
1128 static int __metadata_editor_set_wav_metadata(metadata_editor_s* metadata, metadata_editor_attr_e attribute, const char* value)
1130 int ret = METADATA_EDITOR_ERROR_NONE;
1132 ret = __check_metadata_set_parameter(metadata);
1133 metadata_editor_retvm_if(ret != METADATA_EDITOR_ERROR_NONE, ret, "fail to __check_metadata_set_parameter() [%d]", ret);
1135 // Bring the pointer to actual file type and make tags pointers
1136 TagLib::RIFF::WAV::File* _file = (TagLib::RIFF::WAV::File*)metadata->file;
1137 TagLib::ID3v2::Tag* tag2 = _file->tag();
1138 // Check if the valid tag pointer exist
1140 metadata_editor_error("Error. ID3v2 tag was not created. Can not proceed metadata updating");
1141 return METADATA_EDITOR_ERROR_OPERATION_FAILED;
1144 switch (attribute) { // Check which one of frame type was given for processing
1145 case METADATA_EDITOR_ATTR_ARTIST: return __ID3_setFrameByName(metadata, tag2, "TPE1", value);
1146 case METADATA_EDITOR_ATTR_TITLE: return __ID3_setFrameByName(metadata, tag2, "TIT2", value);
1147 case METADATA_EDITOR_ATTR_ALBUM: return __ID3_setFrameByName(metadata, tag2, "TALB", value);
1148 case METADATA_EDITOR_ATTR_GENRE: return __ID3_setFrameByName(metadata, tag2, "TCON", value);
1149 case METADATA_EDITOR_ATTR_AUTHOR: return __ID3_setFrameByName(metadata, tag2, "TCOM", value);
1150 case METADATA_EDITOR_ATTR_COPYRIGHT: return __ID3_setFrameByName(metadata, tag2, "TCOP", value);
1151 case METADATA_EDITOR_ATTR_DATE: return __ID3_setFrameByName(metadata, tag2, "TDRC", value);
1152 case METADATA_EDITOR_ATTR_DESCRIPTION: return __ID3_setFrameByName(metadata, tag2, "TIT3", value);
1153 case METADATA_EDITOR_ATTR_TRACK_NUM: return __ID3_setFrameByName(metadata, tag2, "TRCK", value);
1154 case METADATA_EDITOR_ATTR_CONDUCTOR: return __ID3_setFrameByName(metadata, tag2, "TPE3", value);
1155 case METADATA_EDITOR_ATTR_COMMENT: return __ID3_setTwixCommentFrame(metadata, NULL, tag2, value);
1156 case METADATA_EDITOR_ATTR_UNSYNCLYRICS: return __ID3_setLyricsFrame(metadata, tag2, value);
1158 return METADATA_EDITOR_ERROR_INVALID_PARAMETER;
1163 // *** This function is used to modify the metadata (frame in tag). But it does not apply changes to file *** //
1164 extern "C" int metadata_editor_set_metadata(metadata_editor_h metadata, metadata_editor_attr_e attribute, const char* value) {
1166 metadata_editor_s* _metadata = (metadata_editor_s*) metadata;
1167 metadata_editor_retvm_if(!_metadata, METADATA_EDITOR_ERROR_INVALID_PARAMETER, "Invalid metadata");
1169 switch (_metadata->filetype) {
1170 case METADATA_EDITOR_FORMAT_MP3:
1171 return __metadata_editor_set_mp3_metadata(_metadata, attribute, value);
1173 case METADATA_EDITOR_FORMAT_MP4:
1174 return __metadata_editor_set_mp4_metadata(_metadata, attribute, value);
1177 case METADATA_EDITOR_FORMAT_FLAC:
1178 return __metadata_editor_set_flac_metadata(_metadata, attribute, value);
1180 case METADATA_EDITOR_FORMAT_OGG_VORBIS:
1181 return __metadata_editor_set_ogg_vorbis_metadata(_metadata, attribute, value);
1183 case METADATA_EDITOR_FORMAT_OGG_FLAC:
1184 return __metadata_editor_set_ogg_flac_metadata(_metadata, attribute, value);
1186 case METADATA_EDITOR_FORMAT_WAV:
1187 return __metadata_editor_set_wav_metadata(_metadata, attribute, value);
1191 metadata_editor_error("Wrong file type");
1192 return METADATA_EDITOR_ERROR_INVALID_PARAMETER;
1196 // *** This function apply all changes done in the tag(s) and update them to file *** //
1197 extern "C" int metadata_editor_update_metadata(metadata_editor_h metadata) {
1198 int ret = METADATA_EDITOR_ERROR_NONE;
1199 metadata_editor_s* _metadata = (metadata_editor_s*) metadata;
1201 ret = __check_metadata_set_parameter(_metadata);
1202 metadata_editor_retvm_if(ret != METADATA_EDITOR_ERROR_NONE, ret, "fail to __check_metadata_set_parameter() [%d]", ret);
1204 switch (_metadata->filetype) {
1205 case METADATA_EDITOR_FORMAT_MP3: {
1206 TagLib::MPEG::File* _file = (TagLib::MPEG::File*)_metadata->file;
1207 TagLib::ID3v1::Tag* tag1 = _file->ID3v1Tag();
1209 if (!tag1 || tag1->isEmpty()) { // If no ID3v1 tag - prevent its creation
1210 if (_file->save(TagLib::MPEG::File::ID3v2 | TagLib::MPEG::File::APE))
1211 return METADATA_EDITOR_ERROR_NONE;
1212 } else { // otherwise - save all tags in file
1213 if (_file->save(TagLib::MPEG::File::AllTags))
1214 return METADATA_EDITOR_ERROR_NONE;
1217 return METADATA_EDITOR_ERROR_OPERATION_FAILED;
1220 case METADATA_EDITOR_FORMAT_MP4: {
1222 case METADATA_EDITOR_FORMAT_FLAC:
1223 case METADATA_EDITOR_FORMAT_OGG_VORBIS:
1224 case METADATA_EDITOR_FORMAT_OGG_FLAC:
1225 case METADATA_EDITOR_FORMAT_WAV:
1227 if (_metadata->file->save())
1228 return METADATA_EDITOR_ERROR_NONE;
1230 return METADATA_EDITOR_ERROR_OPERATION_FAILED;
1234 metadata_editor_error("Wrong file type");
1235 return METADATA_EDITOR_ERROR_INVALID_PARAMETER;
1239 static char * __get_mime_type(const TagLib::String& mime_type)
1241 if (mime_type == MIME_TYPE_JPEG || mime_type == MIME_TYPE_PNG)
1242 return g_strdup(mime_type.toCString());
1247 static char * __get_mime_type_from_cover_art(const TagLib::MP4::CoverArt& cover_art)
1249 if (cover_art.format() == TagLib::MP4::CoverArt::JPEG)
1250 return g_strdup(MIME_TYPE_JPEG);
1251 else if (cover_art.format() == TagLib::MP4::CoverArt::PNG)
1252 return g_strdup(MIME_TYPE_PNG);
1257 static int __get_APIC(TagLib::ID3v2::Tag* tag, int index, void **picture, int *size, char **mime_type)
1259 metadata_editor_retvm_if(!tag, METADATA_EDITOR_ERROR_OPERATION_FAILED, "Error. No ID3v2 tag in file.");
1261 TagLib::ID3v2::FrameList lst = tag->frameListMap()["APIC"];
1263 // Check if there are pictures in the tag
1264 if (lst.isEmpty()) {
1265 metadata_editor_error("No pictures in file");
1266 return METADATA_EDITOR_ERROR_OPERATION_FAILED;
1269 // Check if index is correct or not
1270 if ((index < 0) || (lst.size() <= (uint)index)) {
1271 metadata_editor_error("Index of picture is out of range");
1272 return METADATA_EDITOR_ERROR_INVALID_PARAMETER;
1275 metadata_editor_info("There are %u pictures in file. Start of picture number %d extraction", lst.size(), index);
1277 auto pictureFrame = static_cast<TagLib::ID3v2::AttachedPictureFrame*>(lst[index]);
1279 uint pictureSize = pictureFrame->picture().size();
1280 metadata_editor_retvm_if(pictureSize == 0, METADATA_EDITOR_ERROR_OPERATION_FAILED, "Size of picture is 0");
1282 *picture = g_memdup(pictureFrame->picture().data(), pictureSize);
1283 *size = pictureSize;
1284 *mime_type = __get_mime_type(pictureFrame->mimeType());
1286 return METADATA_EDITOR_ERROR_NONE;
1289 static int __get_mp3_picture(metadata_editor_s* metadata, int index, void **picture, int *size, char **mime_type)
1291 return __get_APIC(dynamic_cast<TagLib::MPEG::File*>(metadata->file)->ID3v2Tag(), index, picture, size, mime_type);
1294 static int __get_mp4_picture(metadata_editor_s* metadata, int index, void **picture, int *size, char **mime_type)
1296 auto tag = dynamic_cast<TagLib::MP4::Tag*>(metadata->file->tag());
1297 metadata_editor_retvm_if(!tag, METADATA_EDITOR_ERROR_OPERATION_FAILED, "Tag does not exist");
1299 if (!(tag->contains("covr"))) {
1300 metadata_editor_error("No item <covr> in file. No pictures in file");
1301 return METADATA_EDITOR_ERROR_OPERATION_FAILED;
1304 TagLib::MP4::CoverArtList lst = tag->item("covr").toCoverArtList();
1306 // Check if the index is in range of CoverArtList Item
1307 if ((index < 0) || ((uint)index >= lst.size())) {
1308 metadata_editor_error("Index of picture is out of range");
1309 return METADATA_EDITOR_ERROR_INVALID_PARAMETER;
1312 auto pictureFrame = static_cast<TagLib::MP4::CoverArt>(lst[index]);
1314 int pictureSize = pictureFrame.data().size();
1315 metadata_editor_retvm_if(pictureSize == 0, METADATA_EDITOR_ERROR_OPERATION_FAILED, "Size of picture is 0");
1317 *picture = g_memdup(pictureFrame.data().data(), pictureSize);
1318 *size = pictureSize;
1319 *mime_type = __get_mime_type_from_cover_art(pictureFrame);
1321 return METADATA_EDITOR_ERROR_NONE;
1325 static int __get_flac_picture(metadata_editor_s* metadata, int index, void **picture, int *size, char **mime_type)
1327 TagLib::FLAC::File* _file = (TagLib::FLAC::File*) metadata->file;
1328 TagLib::List<TagLib::FLAC::Picture*> lst = _file->pictureList();
1330 if (lst.isEmpty()) {
1331 metadata_editor_error("No pictures in FLAC file");
1332 return METADATA_EDITOR_ERROR_OPERATION_FAILED;
1335 // Check if the index is in range of CoverArtList Item
1336 if ((index < 0) || ((uint)index >= lst.size())) {
1337 metadata_editor_error("Index of picture is out of range");
1338 return METADATA_EDITOR_ERROR_INVALID_PARAMETER;
1341 auto pictureFrame = static_cast<TagLib::FLAC::Picture*>(lst[index]);
1343 int pictureSize = pictureFrame->data().size();
1344 metadata_editor_retvm_if(pictureSize == 0, METADATA_EDITOR_ERROR_OPERATION_FAILED, "Size of picture is 0");
1346 *picture = g_memdup(pictureFrame->data().data(), pictureSize);
1347 *size = pictureSize;
1348 *mime_type = __get_mime_type(pictureFrame->mimeType());
1350 return METADATA_EDITOR_ERROR_NONE;
1353 static int __get_wav_picture(metadata_editor_s* metadata, int index, void **picture, int *size, char **mime_type)
1355 TagLib::RIFF::WAV::File* _file = (TagLib::RIFF::WAV::File*)metadata->file;
1357 return __get_APIC(_file->tag(), index, picture, size, mime_type);
1361 // *** This function returns buffer with picture under the specified index and buffer's (picture's) size *** //
1362 extern "C" int metadata_editor_get_picture(metadata_editor_h metadata, int index, void **picture, int *size, char **mime_type) {
1363 int ret = METADATA_EDITOR_ERROR_NONE;
1364 metadata_editor_s* _metadata = (metadata_editor_s*) metadata;
1366 ret = __check_metadata_get_parameter(_metadata, mime_type);
1367 metadata_editor_retvm_if(ret != METADATA_EDITOR_ERROR_NONE, ret, "fail to __check_metadata_get_parameter() [%d]", ret);
1368 metadata_editor_retvm_if(!picture, METADATA_EDITOR_ERROR_INVALID_PARAMETER, "Invalid picture");
1369 metadata_editor_retvm_if(!size, METADATA_EDITOR_ERROR_INVALID_PARAMETER, "Invalid size");
1371 switch (_metadata->filetype) { // Process the file according to the specified file type
1372 case METADATA_EDITOR_FORMAT_MP3:
1373 return __get_mp3_picture(_metadata, index, picture, size, mime_type);
1375 case METADATA_EDITOR_FORMAT_MP4:
1376 return __get_mp4_picture(_metadata, index, picture, size, mime_type);
1379 case METADATA_EDITOR_FORMAT_FLAC:
1380 return __get_flac_picture(_metadata, index, picture, size, mime_type);
1382 case METADATA_EDITOR_FORMAT_WAV:
1383 return __get_wav_picture(_metadata, index, picture, size, mime_type);
1386 metadata_editor_error("Wrong file type");
1387 return METADATA_EDITOR_ERROR_INVALID_PARAMETER;
1391 static int __append_APIC(TagLib::ID3v2::Tag* tag, void *picture, size_t size, const char *mime_type)
1393 metadata_editor_retvm_if(!tag, METADATA_EDITOR_ERROR_OPERATION_FAILED, "Error. No ID3v2 tag in file.");
1395 auto pictureFrame = new TagLib::ID3v2::AttachedPictureFrame();
1397 metadata_editor_info("New APIC frame will be added to the ID3v2 tag");
1399 pictureFrame->setPicture(TagLib::ByteVector((char*)picture, size));
1400 pictureFrame->setType(TagLib::ID3v2::AttachedPictureFrame::FrontCover);
1401 pictureFrame->setMimeType(mime_type);
1403 tag->addFrame(pictureFrame);
1405 return METADATA_EDITOR_ERROR_NONE;
1408 static int __append_mp3_picture(metadata_editor_s* metadata, void *picture ,size_t size, const char *mime_type)
1410 return __append_APIC(dynamic_cast<TagLib::MPEG::File*>(metadata->file)->ID3v2Tag(true), picture, size, mime_type);
1413 static int __append_mp4_picture(metadata_editor_s* metadata, void *picture, size_t size, const char *mime_type)
1415 auto tag = dynamic_cast<TagLib::MP4::Tag*>(metadata->file->tag());
1416 metadata_editor_retvm_if(!tag, METADATA_EDITOR_ERROR_OPERATION_FAILED, "Tag does not exist");
1418 TagLib::MP4::CoverArtList lst;
1419 TagLib::MP4::CoverArt::Format format = TagLib::MP4::CoverArt::Unknown;
1420 if (strncmp(mime_type, MIME_TYPE_JPEG, strlen(MIME_TYPE_JPEG)) == 0)
1421 format = TagLib::MP4::CoverArt::JPEG;
1422 else if (strncmp(mime_type, MIME_TYPE_PNG, strlen(MIME_TYPE_PNG)) == 0)
1423 format = TagLib::MP4::CoverArt::PNG;
1425 if (tag->contains("covr")) {
1426 metadata_editor_info("The item <covr> exists. Adding picture");
1427 lst = tag->item("covr").toCoverArtList();
1430 lst.append(TagLib::MP4::CoverArt(format, TagLib::ByteVector((char*)picture, size)));
1431 tag->setItem("covr", lst);
1433 return METADATA_EDITOR_ERROR_NONE;
1437 static int __append_flac_picture(metadata_editor_s* metadata, void *picture, size_t size, const char *mime_type)
1439 TagLib::FLAC::File* _file = (TagLib::FLAC::File*) metadata->file;
1440 auto frontCover = new TagLib::FLAC::Picture;
1442 metadata_editor_debug_fenter();
1444 frontCover->setData(TagLib::ByteVector((char*)picture, size));
1445 frontCover->setType(TagLib::FLAC::Picture::FrontCover);
1446 frontCover->setMimeType(mime_type);
1448 _file->addPicture(frontCover);
1450 return METADATA_EDITOR_ERROR_NONE;
1453 static int __append_wav_picture(metadata_editor_s* metadata, void *picture, size_t size, const char *mime_type)
1455 return __append_APIC(dynamic_cast<TagLib::ID3v2::Tag*>(metadata->file->tag()), picture, size, mime_type);
1459 // *** This function appends a cover art picture to the file *** //
1460 extern "C" int metadata_editor_append_picture(metadata_editor_h metadata, const char *path) {
1461 int ret = METADATA_EDITOR_ERROR_NONE;
1462 void *picture = NULL;
1464 char *mime_type = NULL;
1466 metadata_editor_s* _metadata = (metadata_editor_s*) metadata;
1468 ret = __check_metadata_set_parameter(_metadata);
1469 metadata_editor_retvm_if(ret != METADATA_EDITOR_ERROR_NONE, ret, "fail to __check_metadata_set_parameter() [%d]", ret);
1470 metadata_editor_retvm_if(!path, METADATA_EDITOR_ERROR_INVALID_PARAMETER, "Invalid path");
1472 ret = __metadata_editor_get_picture_info(path, &picture, &size, &mime_type);
1473 metadata_editor_retvm_if(ret != METADATA_EDITOR_ERROR_NONE, METADATA_EDITOR_ERROR_PERMISSION_DENIED, "File does not exist or you have no rights to open it");
1475 switch (_metadata->filetype) {
1476 case METADATA_EDITOR_FORMAT_MP3:
1477 ret = __append_mp3_picture(_metadata, picture, size, mime_type);
1480 case METADATA_EDITOR_FORMAT_MP4:
1481 ret = __append_mp4_picture(_metadata, picture, size, mime_type);
1485 case METADATA_EDITOR_FORMAT_FLAC:
1486 ret = __append_flac_picture(_metadata, picture, size, mime_type);
1489 case METADATA_EDITOR_FORMAT_WAV:
1490 ret = __append_wav_picture(_metadata, picture, size, mime_type);
1494 metadata_editor_error("Wrong file type");
1495 ret = METADATA_EDITOR_ERROR_NOT_SUPPORTED;
1500 META_SAFE_FREE(picture);
1506 static int __remove_APIC(TagLib::ID3v2::Tag* tag, int index)
1508 metadata_editor_retvm_if(tag == NULL, METADATA_EDITOR_ERROR_OPERATION_FAILED, "Error. ID3v2 tag was not created. Can not proceed metadata updating");
1510 TagLib::ID3v2::FrameList lst = tag->frameListMap()["APIC"];
1511 metadata_editor_retvm_if(lst.isEmpty(), METADATA_EDITOR_ERROR_OPERATION_FAILED, "No pictures in file");
1513 if ((index < 0) || ((uint)index >= lst.size())) {
1514 metadata_editor_error("Index of picture is out of range");
1515 return METADATA_EDITOR_ERROR_INVALID_PARAMETER;
1518 tag->removeFrame(lst[index]);
1520 return METADATA_EDITOR_ERROR_NONE;
1522 static int __remove_mp3_picture(metadata_editor_s* metadata, int index)
1524 return __remove_APIC(dynamic_cast<TagLib::MPEG::File*>(metadata->file)->ID3v2Tag(true), index);
1527 static int __remove_mp4_picture(metadata_editor_s* metadata, int index)
1529 auto tag = dynamic_cast<TagLib::MP4::Tag*>(metadata->file->tag());
1530 metadata_editor_retvm_if(!tag, METADATA_EDITOR_ERROR_OPERATION_FAILED, "Tag does not exist");
1532 if (!(tag->contains("covr"))) {
1533 metadata_editor_error("No item <covr> in file. No pictures in file");
1534 return METADATA_EDITOR_ERROR_OPERATION_FAILED;
1537 TagLib::MP4::CoverArtList lst = tag->item("covr").toCoverArtList();
1539 // Check if the index is in range of CoverArtList Item
1540 if ((index < 0) || ((uint)index >= lst.size())) {
1541 metadata_editor_error("Index of picture is out of range");
1542 return METADATA_EDITOR_ERROR_INVALID_PARAMETER;
1545 metadata_editor_info("The picture number %d will be deleted", index);
1547 for (TagLib::MP4::CoverArtList::Iterator picIt = lst.begin(); picIt != lst.end(); ++picIt, ++i) {
1548 if (i != index) continue;
1553 tag->setItem("covr", lst); //?? FIX ME!
1555 return METADATA_EDITOR_ERROR_NONE;
1559 static int __remove_flac_picture(metadata_editor_s* metadata, int index)
1561 TagLib::FLAC::File* _file = (TagLib::FLAC::File*) metadata->file;
1562 TagLib::List<TagLib::FLAC::Picture*> lst = _file->pictureList();
1564 if (lst.isEmpty()) {
1565 metadata_editor_error("No pictures in file. Nothing to delete");
1566 return METADATA_EDITOR_ERROR_OPERATION_FAILED;
1569 // Check if the index is in range of CoverArtList Item
1570 if ((index < 0) || ((uint)index >= lst.size())) {
1571 metadata_editor_error("Index of picture is out of range");
1572 return METADATA_EDITOR_ERROR_INVALID_PARAMETER;
1575 metadata_editor_info("The picture number %d will be deleted", index);
1577 for (TagLib::List<TagLib::FLAC::Picture*>::Iterator picIt = lst.begin(); picIt != lst.end(); ++picIt, ++i) {
1578 if (i != index) continue;
1579 _file->removePicture(*picIt, true);
1583 return METADATA_EDITOR_ERROR_NONE;
1586 static int __remove_wav_picture(metadata_editor_s* metadata, int index)
1588 return __remove_APIC(dynamic_cast<TagLib::ID3v2::Tag*>(metadata->file->tag()), index);
1592 // *** This function is used to delete picture with specified index *** //
1593 extern "C" int metadata_editor_remove_picture(metadata_editor_h metadata, int index) {
1594 int ret = METADATA_EDITOR_ERROR_NONE;
1595 metadata_editor_s* _metadata = (metadata_editor_s*) metadata;
1597 ret = __check_metadata_set_parameter(_metadata);
1598 metadata_editor_retvm_if(ret != METADATA_EDITOR_ERROR_NONE, ret, "fail to __check_metadata_set_parameter() [%d]", ret);
1600 switch (_metadata->filetype) {
1601 case METADATA_EDITOR_FORMAT_MP3:
1602 return __remove_mp3_picture(_metadata, index);
1604 case METADATA_EDITOR_FORMAT_MP4:
1605 return __remove_mp4_picture(_metadata, index);
1607 case METADATA_EDITOR_FORMAT_FLAC:
1608 return __remove_flac_picture(_metadata, index);
1610 case METADATA_EDITOR_FORMAT_WAV:
1611 return __remove_wav_picture(_metadata, index);
1614 metadata_editor_error("Wrong file type");
1615 return METADATA_EDITOR_ERROR_INVALID_PARAMETER;
1619 extern "C" int metadata_editor_destroy(metadata_editor_h metadata) {
1620 metadata_editor_s *_metadata = (metadata_editor_s*)metadata;
1622 metadata_editor_retvm_if(!_metadata, METADATA_EDITOR_ERROR_INVALID_PARAMETER, "Invalid metadata");
1624 if (_metadata->file)
1625 delete _metadata->file;
1629 return METADATA_EDITOR_ERROR_NONE;