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_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);
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);
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;
57 static int __check_metadata_parameter(metadata_editor_s *metadata)
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");
62 return METADATA_EDITOR_ERROR_NONE;
65 static int __check_metadata_set_parameter(metadata_editor_s *metadata)
67 int ret = METADATA_EDITOR_ERROR_NONE;
69 ret = __check_metadata_parameter(metadata);
70 metadata_editor_retvm_if(ret != METADATA_EDITOR_ERROR_NONE, ret, "fail to __check_metadata_parameter");
72 metadata_editor_retvm_if(metadata->file->readOnly(), METADATA_EDITOR_ERROR_PERMISSION_DENIED, "File is readonly. Unable to modify");
74 return METADATA_EDITOR_ERROR_NONE;
77 static int __check_metadata_get_parameter(metadata_editor_s *metadata, char **value)
79 int ret = METADATA_EDITOR_ERROR_NONE;
81 ret = __check_metadata_parameter(metadata);
82 metadata_editor_retvm_if(ret != METADATA_EDITOR_ERROR_NONE, ret, "fail to __check_metadata_parameter");
84 metadata_editor_retvm_if(!value, METADATA_EDITOR_ERROR_INVALID_PARAMETER, "Invalid value");
86 return METADATA_EDITOR_ERROR_NONE;
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;
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");
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");
114 if (!strcmp(frameID, "TPE1")) { /* artist */
115 str = tag1->artist();
117 } else if (!strcmp(frameID, "TALB")) { /* album */
120 } else if (!strcmp(frameID, "COMM")) { /* comment */
121 str = tag1->comment();
123 } else if (!strcmp(frameID, "TCON")) { /* genre */
126 } else if (!strcmp(frameID, "TIT2")) { /* title */
131 /* Check if we have already found the frame */
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;
142 char buf[META_MAX_BUF_LEN] = {0, };
144 if (!strcmp(frameID, "TRCK")) { /* track */
145 snprintf(buf, META_MAX_BUF_LEN, "%u", tag1->track());
147 } else if (!strcmp(frameID, "TDRC")) { /* data (year) */
148 snprintf(buf, META_MAX_BUF_LEN, "%u", tag1->year());
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;
159 /* The desired frame was not found */
160 return METADATA_EDITOR_ERROR_OPERATION_FAILED;
162 } else { // or frame has data to read
163 metadata_editor_info("The frame %s exists in ID3v2 tag", frameID);
165 // This string is used to copy the value in the frame
166 TagLib::String str = tag2->frameListMap()[frameID][0]->toString();
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");
174 *value = strndup(str.toCString(isUTF), length);
176 return METADATA_EDITOR_ERROR_NONE;
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;
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");
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"))
197 else if (!strcmp(frameID, "TALB"))
199 else if (!strcmp(frameID, "TCON"))
201 else if (!strcmp(frameID, "TIT2"))
203 else if (!strcmp(frameID, "TRCK"))
205 else if (!strcmp(frameID, "TDRC"))
209 return METADATA_EDITOR_ERROR_NONE;
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);
218 fr->setTextEncoding(TagLib::String::UTF8);
219 fr->setText(TagLib::String(value, TagLib::String::UTF8));
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));
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"
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));
242 return METADATA_EDITOR_ERROR_NONE;
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;
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");
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);
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();
262 if (!str.isLatin1()) isUTF = true;
263 metadata_editor_info("String is %sUTF", (isUTF ? "" : "not "));
265 uint length = strlen(str.toCString(isUTF));
266 metadata_editor_retvm_if(length == 0, METADATA_EDITOR_ERROR_NONE, "Empty string");
268 *value = strndup(str.toCString(isUTF), length);
270 return METADATA_EDITOR_ERROR_NONE;
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;
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");
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;
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);
295 fr->setTextEncoding(TagLib::String::UTF8);
296 fr->setText(TagLib::String(value, TagLib::String::UTF8));
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));
303 return METADATA_EDITOR_ERROR_NONE;
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;
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");
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");
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;
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;
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");
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");
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();
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;
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;
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");
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;
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;
374 fr->setText(TagLib::String(value, TagLib::String::UTF8));
375 fr->setTextEncoding(TagLib::String::UTF8);
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));
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);
387 return METADATA_EDITOR_ERROR_NONE;
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;
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");
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;
406 // Check if lyrics frames exist
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;
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));
423 return METADATA_EDITOR_ERROR_NONE;
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;
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");
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");
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)
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;
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;
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");
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");
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;
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;
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");
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");
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())
508 return METADATA_EDITOR_ERROR_NONE;
510 metadata_editor_info("The item <%s> will be added", itemname);
511 itemMap[itemname] = TagLib::MP4::Item(TagLib::String(value, TagLib::String::UTF8));
513 return METADATA_EDITOR_ERROR_NONE;
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;
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");
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");
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())
536 return METADATA_EDITOR_ERROR_NONE;
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;
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;
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);
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");
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
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;
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;
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");
585 const TagLib::Ogg::FieldListMap& fieldMap = xtag->fieldListMap();
586 TagLib::Ogg::FieldListMap::ConstIterator it = fieldMap.find(fieldname);
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)
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;
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;
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");
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;
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;
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;
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);
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;
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;
649 int __metadata_editor_get_file_ext(const char *file_path, char *file_ext, int max_len) {
651 unsigned int path_len = strlen(file_path);
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);
659 /* meet the dir. no ext */
660 if (file_path[i] == '/')
667 int __metadata_editor_get_file_type(const char *path) {
669 char mimetype[255] = {0, };
671 /* get content type and mime type from file. */
672 ret = aul_get_mime_from_file(path, mimetype, sizeof(mimetype));
674 metadata_editor_debug("aul_get_mime_from_file fail.. Now trying to get type by extension");
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");
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;
685 return METADATA_EDITOR_FORMAT_NOTYPE;
688 metadata_editor_debug("mime type : %s", mimetype);
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;
696 return METADATA_EDITOR_FORMAT_NOTYPE;
699 static int __metadata_editor_get_picture_type(const char *path, char **type) {
701 char mimetype[255] = {0, };
703 /* get content type and mime type from file. */
704 ret = aul_get_mime_from_file(path, mimetype, sizeof(mimetype));
706 metadata_editor_debug("aul_get_mime_from_file fail.. Now trying to get type by extension");
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");
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;
719 return METADATA_EDITOR_ERROR_NOT_SUPPORTED;
723 metadata_editor_debug("mime type : %s", mimetype);
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;
734 return METADATA_EDITOR_ERROR_NOT_SUPPORTED;
737 int __metadata_editor_get_picture_info(const char *path, void **picture, size_t *size, char **type) {
740 ret = __metadata_editor_get_picture_type(path, type);
741 if (ret != METADATA_EDITOR_ERROR_NONE)
742 return METADATA_EDITOR_ERROR_OPERATION_FAILED;
745 FILE* fin = fopen(path, "rb");
746 size_t file_size = 0;
749 while (fgetc(fin) != EOF)
753 char picture_buffer[file_size] = {0, };
754 memset(picture_buffer, 0, file_size * sizeof(char));
755 fin = fopen(path, "rb");
757 if(file_size != fread(picture_buffer, 1, file_size, fin)) {
758 metadata_editor_error("fread error");
760 return METADATA_EDITOR_ERROR_OPERATION_FAILED;
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);
772 return METADATA_EDITOR_ERROR_NONE;
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");
780 metadata_editor_s *_metadata = g_new0(metadata_editor_s, 1);
782 _metadata->file = NULL;
783 _metadata->filetype = METADATA_EDITOR_FORMAT_NOTYPE; // Specify file type out of range
785 // Save the structure in the metadata
786 *metadata = (metadata_editor_h)_metadata;
788 return METADATA_EDITOR_ERROR_NONE;
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;
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");
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;
805 metadata_editor_error("Fail to open path");
806 return METADATA_EDITOR_ERROR_FILE_EXISTS;
810 media_type = __metadata_editor_get_file_type(path);
812 if (_metadata->file) {
813 metadata_editor_info("file free [%p]", _metadata->file);
814 delete _metadata->file;
816 _metadata->file = NULL;
817 _metadata->filetype = METADATA_EDITOR_FORMAT_NOTYPE;
821 switch (media_type) {
822 case METADATA_EDITOR_FORMAT_MP3:
823 _file = new TagLib::MPEG::File(path);
826 case METADATA_EDITOR_FORMAT_MP4:
827 _file = new TagLib::MP4::File(path);
831 case METADATA_EDITOR_FORMAT_FLAC:
832 _file = new TagLib::FLAC::File(path);
835 case METADATA_EDITOR_FORMAT_OGG_VORBIS:
836 _file = new TagLib::Ogg::Vorbis::File(path);
839 case METADATA_EDITOR_FORMAT_OGG_FLAC:
840 _file = new TagLib::Ogg::FLAC::File(path);
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);
850 metadata_editor_error("Wrong file type");
851 return METADATA_EDITOR_ERROR_NOT_SUPPORTED;
853 } catch (const std::bad_alloc &ex) {
854 metadata_editor_retvm_if(!_file, METADATA_EDITOR_ERROR_OUT_OF_MEMORY, "OUT_OF_MEMORY");
857 if (!_file->isOpen()) {
858 metadata_editor_error("The file was not found. Pointer address is %p", _file);
860 return METADATA_EDITOR_ERROR_PERMISSION_DENIED;
863 _metadata->file = _file;
864 _metadata->filetype = media_type;
866 return METADATA_EDITOR_ERROR_NONE;
869 static int __metadata_editor_get_mp3_metadata(metadata_editor_s *metadata, metadata_editor_attr_e attribute, char **value)
871 int ret = METADATA_EDITOR_ERROR_NONE;
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);
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();
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);
896 return METADATA_EDITOR_ERROR_INVALID_PARAMETER;
900 static int __metadata_editor_get_mp4_metadata(metadata_editor_s *metadata, metadata_editor_attr_e attribute, char **value)
902 int ret = METADATA_EDITOR_ERROR_NONE;
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);
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);
922 return METADATA_EDITOR_ERROR_INVALID_PARAMETER;
927 static int __metadata_editor_get_flac_metadata(metadata_editor_s *metadata, metadata_editor_attr_e attribute, char **value)
929 int ret = METADATA_EDITOR_ERROR_NONE;
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);
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");
940 return METADATA_EDITOR_ERROR_OPERATION_FAILED;
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);
957 return METADATA_EDITOR_ERROR_INVALID_PARAMETER;
961 static int __metadata_editor_get_ogg_vorbis_metadata(metadata_editor_s *metadata, metadata_editor_attr_e attribute, char **value)
963 int ret = METADATA_EDITOR_ERROR_NONE;
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);
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");
974 return METADATA_EDITOR_ERROR_OPERATION_FAILED;
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);
990 return METADATA_EDITOR_ERROR_INVALID_PARAMETER;
994 static int __metadata_editor_get_ogg_flac_metadata(metadata_editor_s *metadata, metadata_editor_attr_e attribute, char **value)
996 int ret = METADATA_EDITOR_ERROR_NONE;
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);
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");
1007 return METADATA_EDITOR_ERROR_OPERATION_FAILED;
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);
1023 return METADATA_EDITOR_ERROR_INVALID_PARAMETER;
1027 static int __metadata_editor_get_wav_metadata(metadata_editor_s *metadata, metadata_editor_attr_e attribute, char **value)
1029 int ret = METADATA_EDITOR_ERROR_NONE;
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);
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();
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");
1041 return METADATA_EDITOR_ERROR_OPERATION_FAILED;
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);
1059 return METADATA_EDITOR_ERROR_INVALID_PARAMETER;
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) {
1067 metadata_editor_s *_metadata = (metadata_editor_s*)metadata;
1068 metadata_editor_retvm_if(!_metadata, METADATA_EDITOR_ERROR_INVALID_PARAMETER, "Invalid metadata");
1070 switch (_metadata->filetype) {
1071 case METADATA_EDITOR_FORMAT_MP3:
1072 return __metadata_editor_get_mp3_metadata(_metadata, attribute, value);
1074 case METADATA_EDITOR_FORMAT_MP4:
1075 return __metadata_editor_get_mp4_metadata(_metadata, attribute, value);
1078 case METADATA_EDITOR_FORMAT_FLAC:
1079 return __metadata_editor_get_flac_metadata(_metadata, attribute, value);
1081 case METADATA_EDITOR_FORMAT_OGG_VORBIS:
1082 return __metadata_editor_get_ogg_vorbis_metadata(_metadata, attribute, value);
1084 case METADATA_EDITOR_FORMAT_OGG_FLAC:
1085 return __metadata_editor_get_ogg_flac_metadata(_metadata, attribute, value);
1087 case METADATA_EDITOR_FORMAT_WAV:
1088 return __metadata_editor_get_wav_metadata(_metadata, attribute, value);
1092 metadata_editor_error("Wrong file type [%d]", _metadata->filetype);
1093 return METADATA_EDITOR_ERROR_INVALID_PARAMETER;
1097 static int __metadata_editor_set_mp3_metadata(metadata_editor_s* metadata, metadata_editor_attr_e attribute, const char* value)
1099 int ret = METADATA_EDITOR_ERROR_NONE;
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);
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);
1109 metadata_editor_retvm_if(tag2 == NULL, METADATA_EDITOR_ERROR_OPERATION_FAILED, "Error. ID3v2 tag was not created. Can not proceed metadata updating");
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);
1125 return METADATA_EDITOR_ERROR_INVALID_PARAMETER;
1129 static int __metadata_editor_set_mp4_metadata(metadata_editor_s* metadata, metadata_editor_attr_e attribute, const char* value)
1131 int ret = METADATA_EDITOR_ERROR_NONE;
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);
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);
1150 return METADATA_EDITOR_ERROR_INVALID_PARAMETER;
1155 static int __metadata_editor_set_flac_metadata(metadata_editor_s* metadata, metadata_editor_attr_e attribute, const char* value)
1157 int ret = METADATA_EDITOR_ERROR_NONE;
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);
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;
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);
1183 return METADATA_EDITOR_ERROR_INVALID_PARAMETER;
1187 static int __metadata_editor_set_ogg_vorbis_metadata(metadata_editor_s* metadata, metadata_editor_attr_e attribute, const char* value)
1189 int ret = METADATA_EDITOR_ERROR_NONE;
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);
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;
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);
1215 return METADATA_EDITOR_ERROR_INVALID_PARAMETER;
1219 static int __metadata_editor_set_ogg_flac_metadata(metadata_editor_s* metadata, metadata_editor_attr_e attribute, const char* value)
1221 int ret = METADATA_EDITOR_ERROR_NONE;
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);
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;
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);
1247 return METADATA_EDITOR_ERROR_INVALID_PARAMETER;
1251 static int __metadata_editor_set_wav_metadata(metadata_editor_s* metadata, metadata_editor_attr_e attribute, const char* value)
1253 int ret = METADATA_EDITOR_ERROR_NONE;
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);
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
1263 metadata_editor_error("Error. ID3v2 tag was not created. Can not proceed metadata updating");
1264 return METADATA_EDITOR_ERROR_OPERATION_FAILED;
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);
1281 return METADATA_EDITOR_ERROR_INVALID_PARAMETER;
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) {
1289 metadata_editor_s* _metadata = (metadata_editor_s*) metadata;
1290 metadata_editor_retvm_if(!_metadata, METADATA_EDITOR_ERROR_INVALID_PARAMETER, "Invalid metadata");
1292 switch (_metadata->filetype) {
1293 case METADATA_EDITOR_FORMAT_MP3:
1294 return __metadata_editor_set_mp3_metadata(_metadata, attribute, value);
1296 case METADATA_EDITOR_FORMAT_MP4:
1297 return __metadata_editor_set_mp4_metadata(_metadata, attribute, value);
1300 case METADATA_EDITOR_FORMAT_FLAC:
1301 return __metadata_editor_set_flac_metadata(_metadata, attribute, value);
1303 case METADATA_EDITOR_FORMAT_OGG_VORBIS:
1304 return __metadata_editor_set_ogg_vorbis_metadata(_metadata, attribute, value);
1306 case METADATA_EDITOR_FORMAT_OGG_FLAC:
1307 return __metadata_editor_set_ogg_flac_metadata(_metadata, attribute, value);
1309 case METADATA_EDITOR_FORMAT_WAV:
1310 return __metadata_editor_set_wav_metadata(_metadata, attribute, value);
1314 metadata_editor_error("Wrong file type");
1315 return METADATA_EDITOR_ERROR_INVALID_PARAMETER;
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;
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);
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();
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;
1340 return METADATA_EDITOR_ERROR_OPERATION_FAILED;
1343 case METADATA_EDITOR_FORMAT_MP4: {
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:
1350 if (_metadata->file->save())
1351 return METADATA_EDITOR_ERROR_NONE;
1353 return METADATA_EDITOR_ERROR_OPERATION_FAILED;
1357 metadata_editor_error("Wrong file type");
1358 return METADATA_EDITOR_ERROR_INVALID_PARAMETER;
1362 static char * __get_mime_type(const TagLib::String& mime_type)
1364 if (mime_type == MIME_TYPE_JPEG || mime_type == MIME_TYPE_PNG)
1365 return g_strdup(mime_type.toCString());
1370 static char * __get_mime_type_from_cover_art(const TagLib::MP4::CoverArt& cover_art)
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);
1380 static int __get_APIC(TagLib::ID3v2::Tag* tag, int index, void **picture, int *size, char **mime_type)
1382 metadata_editor_retvm_if(!tag, METADATA_EDITOR_ERROR_OPERATION_FAILED, "Error. No ID3v2 tag in file.");
1384 TagLib::ID3v2::FrameList lst = tag->frameListMap()["APIC"];
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;
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;
1398 metadata_editor_info("There are %u pictures in file. Start of picture number %d extraction", lst.size(), index);
1400 auto pictureFrame = static_cast<TagLib::ID3v2::AttachedPictureFrame*>(lst[index]);
1402 uint pictureSize = pictureFrame->picture().size();
1403 metadata_editor_retvm_if(pictureSize == 0, METADATA_EDITOR_ERROR_OPERATION_FAILED, "Size of picture is 0");
1405 *picture = g_memdup(pictureFrame->picture().data(), pictureSize);
1406 *size = pictureSize;
1407 *mime_type = __get_mime_type(pictureFrame->mimeType());
1409 return METADATA_EDITOR_ERROR_NONE;
1412 static int __get_mp3_picture(metadata_editor_s* metadata, int index, void **picture, int *size, char **mime_type)
1414 TagLib::MPEG::File* _file = (TagLib::MPEG::File*)metadata->file;
1416 return __get_APIC(_file->ID3v2Tag(), index, picture, size, mime_type);
1419 static int __get_mp4_picture(metadata_editor_s* metadata, int index, void **picture, int *size, char **mime_type)
1421 TagLib::MP4::File* _file = (TagLib::MP4::File*) metadata->file;
1422 TagLib::MP4::Tag* tag = _file->tag();
1424 metadata_editor_retvm_if(!tag, METADATA_EDITOR_ERROR_OPERATION_FAILED, "Tag does not exist");
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;
1431 TagLib::MP4::CoverArtList lst = tag->item("covr").toCoverArtList();
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;
1439 auto pictureFrame = static_cast<TagLib::MP4::CoverArt>(lst[index]);
1441 int pictureSize = pictureFrame.data().size();
1442 metadata_editor_retvm_if(pictureSize == 0, METADATA_EDITOR_ERROR_OPERATION_FAILED, "Size of picture is 0");
1444 *picture = g_memdup(pictureFrame.data().data(), pictureSize);
1445 *size = pictureSize;
1446 *mime_type = __get_mime_type_from_cover_art(pictureFrame);
1448 return METADATA_EDITOR_ERROR_NONE;
1452 static int __get_flac_picture(metadata_editor_s* metadata, int index, void **picture, int *size, char **mime_type)
1454 TagLib::FLAC::File* _file = (TagLib::FLAC::File*) metadata->file;
1455 TagLib::List<TagLib::FLAC::Picture*> lst = _file->pictureList();
1457 if (lst.isEmpty()) {
1458 metadata_editor_error("No pictures in FLAC file");
1459 return METADATA_EDITOR_ERROR_OPERATION_FAILED;
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;
1468 auto pictureFrame = static_cast<TagLib::FLAC::Picture*>(lst[index]);
1470 int pictureSize = pictureFrame->data().size();
1471 metadata_editor_retvm_if(pictureSize == 0, METADATA_EDITOR_ERROR_OPERATION_FAILED, "Size of picture is 0");
1473 *picture = g_memdup(pictureFrame->data().data(), pictureSize);
1474 *size = pictureSize;
1475 *mime_type = __get_mime_type(pictureFrame->mimeType());
1477 return METADATA_EDITOR_ERROR_NONE;
1480 static int __get_wav_picture(metadata_editor_s* metadata, int index, void **picture, int *size, char **mime_type)
1482 TagLib::RIFF::WAV::File* _file = (TagLib::RIFF::WAV::File*)metadata->file;
1484 return __get_APIC(_file->tag(), index, picture, size, mime_type);
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;
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");
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);
1502 case METADATA_EDITOR_FORMAT_MP4:
1503 return __get_mp4_picture(_metadata, index, picture, size, mime_type);
1506 case METADATA_EDITOR_FORMAT_FLAC:
1507 return __get_flac_picture(_metadata, index, picture, size, mime_type);
1509 case METADATA_EDITOR_FORMAT_WAV:
1510 return __get_wav_picture(_metadata, index, picture, size, mime_type);
1513 metadata_editor_error("Wrong file type");
1514 return METADATA_EDITOR_ERROR_INVALID_PARAMETER;
1518 static int __append_APIC(TagLib::ID3v2::Tag* tag, void *picture, size_t size, const char *mime_type)
1520 metadata_editor_retvm_if(!tag, METADATA_EDITOR_ERROR_OPERATION_FAILED, "Error. No ID3v2 tag in file.");
1522 auto pictureFrame = new TagLib::ID3v2::AttachedPictureFrame();
1524 metadata_editor_info("New APIC frame will be added to the ID3v2 tag");
1526 pictureFrame->setPicture(TagLib::ByteVector((char*)picture, size));
1527 pictureFrame->setType(TagLib::ID3v2::AttachedPictureFrame::FrontCover);
1528 pictureFrame->setMimeType(mime_type);
1530 tag->addFrame(pictureFrame);
1532 return METADATA_EDITOR_ERROR_NONE;
1535 static int __append_mp3_picture(metadata_editor_s* metadata, void *picture ,size_t size, const char *mime_type)
1537 return __append_APIC(dynamic_cast<TagLib::MPEG::File*>(metadata->file)->ID3v2Tag(true), picture, size, mime_type);
1540 static int __append_mp4_picture(metadata_editor_s* metadata, void *picture, size_t size, const char *mime_type)
1542 auto tag = dynamic_cast<TagLib::MP4::Tag*>(metadata->file->tag());
1544 metadata_editor_retvm_if(!tag, METADATA_EDITOR_ERROR_OPERATION_FAILED, "Tag was not created");
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;
1553 if (tag->contains("covr")) {
1554 metadata_editor_info("The item <covr> exists. Adding picture");
1555 lst = tag->item("covr").toCoverArtList();
1558 lst.append(TagLib::MP4::CoverArt(format, TagLib::ByteVector((char*)picture, size)));
1559 tag->setItem("covr", lst);
1561 return METADATA_EDITOR_ERROR_NONE;
1565 static int __append_flac_picture(metadata_editor_s* metadata, void *picture, size_t size, const char *mime_type)
1567 TagLib::FLAC::File* _file = (TagLib::FLAC::File*) metadata->file;
1568 auto frontCover = new TagLib::FLAC::Picture;
1570 metadata_editor_debug_fenter();
1572 frontCover->setData(TagLib::ByteVector((char*)picture, size));
1573 frontCover->setType(TagLib::FLAC::Picture::FrontCover);
1574 frontCover->setMimeType(mime_type);
1576 _file->addPicture(frontCover);
1578 return METADATA_EDITOR_ERROR_NONE;
1581 static int __append_wav_picture(metadata_editor_s* metadata, void *picture, size_t size, const char *mime_type)
1583 return __append_APIC(dynamic_cast<TagLib::ID3v2::Tag*>(metadata->file->tag()), picture, size, mime_type);
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;
1592 char *mime_type = NULL;
1594 metadata_editor_s* _metadata = (metadata_editor_s*) metadata;
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");
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");
1603 switch (_metadata->filetype) {
1604 case METADATA_EDITOR_FORMAT_MP3:
1605 ret = __append_mp3_picture(_metadata, picture, size, mime_type);
1608 case METADATA_EDITOR_FORMAT_MP4:
1609 ret = __append_mp4_picture(_metadata, picture, size, mime_type);
1613 case METADATA_EDITOR_FORMAT_FLAC:
1614 ret = __append_flac_picture(_metadata, picture, size, mime_type);
1617 case METADATA_EDITOR_FORMAT_WAV:
1618 ret = __append_wav_picture(_metadata, picture, size, mime_type);
1622 metadata_editor_error("Wrong file type");
1623 ret = METADATA_EDITOR_ERROR_NOT_SUPPORTED;
1628 META_SAFE_FREE(picture);
1634 static int __remove_APIC(TagLib::ID3v2::Tag* tag, int index)
1636 metadata_editor_retvm_if(tag == NULL, METADATA_EDITOR_ERROR_OPERATION_FAILED, "Error. ID3v2 tag was not created. Can not proceed metadata updating");
1638 TagLib::ID3v2::FrameList lst = tag->frameListMap()["APIC"];
1639 metadata_editor_retvm_if(lst.isEmpty(), METADATA_EDITOR_ERROR_OPERATION_FAILED, "No pictures in file");
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;
1646 tag->removeFrame(lst[index]);
1648 return METADATA_EDITOR_ERROR_NONE;
1650 static int __remove_mp3_picture(metadata_editor_s* metadata, int index)
1652 return __remove_APIC(dynamic_cast<TagLib::MPEG::File*>(metadata->file)->ID3v2Tag(true), index);
1655 static int __remove_mp4_picture(metadata_editor_s* metadata, int index)
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.");
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;
1665 TagLib::MP4::CoverArtList lst = tag->item("covr").toCoverArtList();
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;
1673 metadata_editor_info("The picture number %d will be deleted", index);
1675 for (TagLib::MP4::CoverArtList::Iterator picIt = lst.begin(); picIt != lst.end(); ++picIt, ++i) {
1676 if (i != index) continue;
1681 tag->setItem("covr", lst); //?? FIX ME!
1683 return METADATA_EDITOR_ERROR_NONE;
1687 static int __remove_flac_picture(metadata_editor_s* metadata, int index)
1689 TagLib::FLAC::File* _file = (TagLib::FLAC::File*) metadata->file;
1690 TagLib::List<TagLib::FLAC::Picture*> lst = _file->pictureList();
1692 if (lst.isEmpty()) {
1693 metadata_editor_error("No pictures in file. Nothing to delete");
1694 return METADATA_EDITOR_ERROR_OPERATION_FAILED;
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;
1703 metadata_editor_info("The picture number %d will be deleted", index);
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);
1711 return METADATA_EDITOR_ERROR_NONE;
1714 static int __remove_wav_picture(metadata_editor_s* metadata, int index)
1716 return __remove_APIC(dynamic_cast<TagLib::ID3v2::Tag*>(metadata->file->tag()), index);
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;
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);
1728 switch (_metadata->filetype) {
1729 case METADATA_EDITOR_FORMAT_MP3:
1730 return __remove_mp3_picture(_metadata, index);
1732 case METADATA_EDITOR_FORMAT_MP4:
1733 return __remove_mp4_picture(_metadata, index);
1735 case METADATA_EDITOR_FORMAT_FLAC:
1736 return __remove_flac_picture(_metadata, index);
1738 case METADATA_EDITOR_FORMAT_WAV:
1739 return __remove_wav_picture(_metadata, index);
1742 metadata_editor_error("Wrong file type");
1743 return METADATA_EDITOR_ERROR_INVALID_PARAMETER;
1747 extern "C" int metadata_editor_destroy(metadata_editor_h metadata) {
1748 metadata_editor_s *_metadata = (metadata_editor_s*)metadata;
1750 metadata_editor_retvm_if(!_metadata, METADATA_EDITOR_ERROR_INVALID_PARAMETER, "Invalid metadata");
1752 if (_metadata->file)
1753 delete _metadata->file;
1757 return METADATA_EDITOR_ERROR_NONE;