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 static int __ID3_getTwixFrameByName(metadata_editor_s* _metadata, TagLib::ID3v1::Tag* tag1, TagLib::ID3v2::Tag* tag2, const char* frameID, char** value);
27 static int __ID3_setTwixFrameByName(metadata_editor_s* _metadata, TagLib::ID3v1::Tag* tag1, TagLib::ID3v2::Tag* tag2, const char* frameID, const char* value);
28 static int __ID3_getFrameByName(metadata_editor_s* _metadata, TagLib::ID3v2::Tag* tag2, const char* frameID, char** value);
29 static int __ID3_setFrameByName(metadata_editor_s* _metadata, TagLib::ID3v2::Tag* tag2, const char* frameID, const char* value);
30 static int __ID3_getNumberOfPictures(metadata_editor_s* _metadata, TagLib::ID3v2::Tag* tag2, char** value);
31 static int __ID3_getLyricsFrame(metadata_editor_s* _metadata, TagLib::ID3v2::Tag* tag2, char** value);
32 static int __ID3_setTwixCommentFrame(metadata_editor_s* _metadata, TagLib::ID3v1::Tag* tag1, TagLib::ID3v2::Tag* tag2, const char* value);
33 static int __ID3_setLyricsFrame(metadata_editor_s* _metadata, TagLib::ID3v2::Tag* tag2, const char* value);
34 static int __MP4_getStringItem(metadata_editor_s* _metadata, const char* itemname, char** value);
35 static int __MP4_getIntegerItem(metadata_editor_s* _metadata, const char* itemname, char** value);
36 static int __MP4_updateStringItem(metadata_editor_s* _metadata, const char* itemname, const char* value);
37 static int __MP4_updateIntegerItem(metadata_editor_s* _metadata, const char* itemname, const char* value);
38 static int __MP4_getNumberOfPictures(metadata_editor_s* _metadata, char** value);
40 static int __xiph_getFieldValue(metadata_editor_s* _metadata, TagLib::Ogg::XiphComment* xtag, const char* fieldname, char** value);
41 static int __xiph_updateFieldValue(metadata_editor_s* _metadata, TagLib::Ogg::XiphComment* xtag, const char* fieldname, const char* value);
42 static int __FLAC_getNumberOfPictures(metadata_editor_s* _metadata, 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");
58 metadata_editor_retvm_if(!metadata->isOpen, METADATA_EDITOR_ERROR_PERMISSION_DENIED, "File does not exist or you have no rights to open it");
60 return METADATA_EDITOR_ERROR_NONE;
63 static int __check_metadata_set_parameter(metadata_editor_s *metadata)
65 int ret = METADATA_EDITOR_ERROR_NONE;
67 ret = __check_metadata_parameter(metadata);
68 metadata_editor_retvm_if(ret != METADATA_EDITOR_ERROR_NONE, ret, "fail to __check_metadata_parameter");
70 metadata_editor_retvm_if(metadata->isReadOnly, METADATA_EDITOR_ERROR_PERMISSION_DENIED, "File is readonly. Unable to modify");
72 return METADATA_EDITOR_ERROR_NONE;
75 static int __check_metadata_get_parameter(metadata_editor_s *metadata, char **value)
77 int ret = METADATA_EDITOR_ERROR_NONE;
79 ret = __check_metadata_parameter(metadata);
80 metadata_editor_retvm_if(ret != METADATA_EDITOR_ERROR_NONE, ret, "fail to __check_metadata_parameter");
82 metadata_editor_retvm_if(!value, METADATA_EDITOR_ERROR_INVALID_PARAMETER, "Invalid value");
84 return METADATA_EDITOR_ERROR_NONE;
87 // *** This is an auxiliary function that is used to get the frame value *** //
88 // *** It operates with frames that exists both in ID3v1 and ID3v2 tags *** //
89 static int __ID3_getTwixFrameByName(metadata_editor_s* _metadata, TagLib::ID3v1::Tag* tag1, TagLib::ID3v2::Tag* tag2, const char* frameID, char** value) {
90 int ret = METADATA_EDITOR_ERROR_NONE;
92 ret = __check_metadata_get_parameter(_metadata, value);
93 metadata_editor_retvm_if(ret != METADATA_EDITOR_ERROR_NONE, ret, "fail to __check_metadata_get_parameter() [%d]", ret);
94 metadata_editor_retvm_if(!frameID, METADATA_EDITOR_ERROR_INVALID_PARAMETER, "Invalid frameID");
98 // Check if the frame is empty (nothing to read) or ID3v2 tag does not exist
99 if (!tag2 || tag2->frameListMap()[frameID].isEmpty()) {
100 metadata_editor_info("The frame %s in ID3v2 tag is empty", frameID);
101 // Check if the tag ID3v1 is also empty or does not exist
102 if (!tag1 || tag1->isEmpty()) {
103 metadata_editor_info("The frame %s in ID3v1 tag is empty as well", frameID);
104 return METADATA_EDITOR_ERROR_NONE;
105 } else { // if not - read the frame you need there
106 metadata_editor_info("Reading data from ID3v1 tag");
112 if (!strcmp(frameID, "TPE1")) { /* artist */
113 str = tag1->artist();
115 } else if (!strcmp(frameID, "TALB")) { /* album */
118 } else if (!strcmp(frameID, "COMM")) { /* comment */
119 str = tag1->comment();
121 } else if (!strcmp(frameID, "TCON")) { /* genre */
124 } else if (!strcmp(frameID, "TIT2")) { /* title */
129 /* Check if we have already found the frame */
132 if (!str.isLatin1()) isUTF = true;
133 metadata_editor_info("String is %sUTF", (isUTF ? "" : "not "));
134 length = strlen(str.toCString(isUTF));
135 metadata_editor_retvm_if(length == 0, METADATA_EDITOR_ERROR_NONE, "Empty string");
136 *value = strndup(str.toCString(isUTF), length);
137 return METADATA_EDITOR_ERROR_NONE;
140 char buf[META_MAX_BUF_LEN] = {0, };
142 if (!strcmp(frameID, "TRCK")) { /* track */
143 snprintf(buf, META_MAX_BUF_LEN, "%u", tag1->track());
145 } else if (!strcmp(frameID, "TDRC")) { /* data (year) */
146 snprintf(buf, META_MAX_BUF_LEN, "%u", tag1->year());
151 length = strlen(buf);
152 metadata_editor_retvm_if(length == 0, METADATA_EDITOR_ERROR_NONE, "Empty string");
153 *value = strndup(buf, length);
154 return METADATA_EDITOR_ERROR_NONE;
157 /* The desired frame was not found */
158 return METADATA_EDITOR_ERROR_OPERATION_FAILED;
160 } else { // or frame has data to read
161 metadata_editor_info("The frame %s exists in ID3v2 tag", frameID);
163 // This string is used to copy the value in the frame
164 TagLib::String str = tag2->frameListMap()[frameID][0]->toString();
167 if (!str.isLatin1()) isUTF = true;
168 metadata_editor_info("String is %sUTF", (isUTF ? "" : "not "));
169 uint length = strlen(str.toCString(isUTF));
170 metadata_editor_retvm_if(length == 0, METADATA_EDITOR_ERROR_NONE, "Empty string");
172 *value = strndup(str.toCString(isUTF), length);
174 return METADATA_EDITOR_ERROR_NONE;
178 // *** This is an auxiliary function that is used to write the new value to the frame *** //
179 // *** It operates with frames that exists both in ID3v1 and ID3v2 tags *** //
180 static int __ID3_setTwixFrameByName(metadata_editor_s* _metadata, TagLib::ID3v1::Tag* tag1, TagLib::ID3v2::Tag* tag2, const char* frameID, const char* value) {
181 int ret = METADATA_EDITOR_ERROR_NONE;
183 ret = __check_metadata_set_parameter(_metadata);
184 metadata_editor_retvm_if(ret != METADATA_EDITOR_ERROR_NONE, ret, "fail to __check_metadata_set_parameter() [%d]", ret);
185 metadata_editor_retvm_if(!frameID, METADATA_EDITOR_ERROR_INVALID_PARAMETER, "Invalid frameID");
186 metadata_editor_retvm_if(!tag2, METADATA_EDITOR_ERROR_OPERATION_FAILED, "Error. ID3v2 tag was not created. Can not proceed metadata updating");
188 // If the pointer is NULL or c-string is empty - handle as request for deletion
189 if (!value || (*value == '\0')) {
190 metadata_editor_info("Request for frame %s deletion", frameID);
191 tag2->removeFrames(frameID);
192 if (tag1 && !tag1->isEmpty()) {
193 if (!strcmp(frameID, "TPE1"))
195 else if (!strcmp(frameID, "TALB"))
197 else if (!strcmp(frameID, "TCON"))
199 else if (!strcmp(frameID, "TIT2"))
201 else if (!strcmp(frameID, "TRCK"))
203 else if (!strcmp(frameID, "TDRC"))
207 return METADATA_EDITOR_ERROR_NONE;
210 // Check if the frame is empty (must create the frame before writing the data)
211 if (tag2->frameListMap()[frameID].isEmpty()) {
212 metadata_editor_info("The frame %s does not exist. Creating", frameID);
213 // This is a common frame type for textural frames except comment frame
214 TagLib::ID3v2::TextIdentificationFrame* fr = new TagLib::ID3v2::TextIdentificationFrame(frameID);
215 metadata_editor_retvm_if(fr == NULL, METADATA_EDITOR_ERROR_OUT_OF_MEMORY, "OUT_OF_MEMORY");
217 fr->setTextEncoding(TagLib::String::UTF8);
218 fr->setText(TagLib::String(value, TagLib::String::UTF8));
220 } else { // if not - just modify the data in the existing frame
221 metadata_editor_info("The frame %s exists. Changing", frameID);
222 tag2->frameListMap()[frameID][0]->setText(TagLib::String(value, TagLib::String::UTF8));
225 if (tag1 && !tag1->isEmpty()) { // Check if ID3v1 tag exists. Must copy data if yes.
226 metadata_editor_info("ID3v1 tag also exists. Copying frame");
227 if (!strcmp(frameID, "TPE1"))
228 tag1->setArtist(value);
229 else if (!strcmp(frameID, "TALB"))
230 tag1->setAlbum(value);
231 else if (!strcmp(frameID, "TCON")) // Genre in ID3v1 is enumeration, so can not write it with "value"
233 else if (!strcmp(frameID, "TIT2"))
234 tag1->setTitle(value);
235 else if (!strcmp(frameID, "TRCK"))
236 tag1->setTrack(atoi(value));
237 else if (!strcmp(frameID, "TDRC"))
238 tag1->setYear(atoi(value));
241 return METADATA_EDITOR_ERROR_NONE;
244 // *** This function reads frames that exist only in ID3v2 tag *** //
245 static int __ID3_getFrameByName(metadata_editor_s* _metadata, TagLib::ID3v2::Tag* tag2, const char* frameID, 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(!frameID, METADATA_EDITOR_ERROR_INVALID_PARAMETER, "Invalid frameID");
254 // Check if the frame is empty (nothing to read) or ID3v2 tag does not exist
255 metadata_editor_retvm_if(!tag2 || tag2->frameListMap()[frameID].isEmpty(), METADATA_EDITOR_ERROR_NONE, "The frame %s does not exist", frameID);
257 metadata_editor_info("The frame %s exists", frameID);
258 // This string is used to copy the value in the frame
259 TagLib::String str = tag2->frameListMap()[frameID][0]->toString();
261 if (!str.isLatin1()) isUTF = true;
262 metadata_editor_info("String is %sUTF", (isUTF ? "" : "not "));
264 uint length = strlen(str.toCString(isUTF));
265 metadata_editor_retvm_if(length == 0, METADATA_EDITOR_ERROR_NONE, "Empty string");
267 *value = strndup(str.toCString(isUTF), length);
269 return METADATA_EDITOR_ERROR_NONE;
272 // *** This function writes frames that exist only in ID3v2 tag *** //
273 static int __ID3_setFrameByName(metadata_editor_s* _metadata, TagLib::ID3v2::Tag* tag2, const char* frameID, const char* value) {
274 int ret = METADATA_EDITOR_ERROR_NONE;
276 ret = __check_metadata_set_parameter(_metadata);
277 metadata_editor_retvm_if(ret != METADATA_EDITOR_ERROR_NONE, ret, "fail to __check_metadata_set_parameter() [%d]", ret);
278 metadata_editor_retvm_if(!frameID, METADATA_EDITOR_ERROR_INVALID_PARAMETER, "Invalid frameID");
279 metadata_editor_retvm_if(!tag2, METADATA_EDITOR_ERROR_OPERATION_FAILED, "Error. ID3v2 tag was not created. Can not proceed metadata updating");
281 // If the pointer is NULL or c-string is empty - handle as request for deletion
282 if (!value || (*value == '\0')) {
283 metadata_editor_info("Request for frame %s deletion", frameID);
284 tag2->removeFrames(frameID);
285 return METADATA_EDITOR_ERROR_NONE;
288 // Check if the ID3v2 tag exists
289 if (tag2->frameListMap()[frameID].isEmpty()) {
290 metadata_editor_info("The frame %s does not exist. Creating", frameID);
291 // This is a common frame type for textural frames except comment frame
292 TagLib::ID3v2::TextIdentificationFrame* fr = new TagLib::ID3v2::TextIdentificationFrame(frameID);
293 metadata_editor_retvm_if(fr == NULL, METADATA_EDITOR_ERROR_OUT_OF_MEMORY, "OUT_OF_MEMORY");
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 TagLib::ID3v2::UnsynchronizedLyricsFrame* 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 TagLib::ID3v2::CommentsFrame* fr = new TagLib::ID3v2::CommentsFrame;
373 metadata_editor_retvm_if(fr == NULL, METADATA_EDITOR_ERROR_OUT_OF_MEMORY, "OUT_OF_MEMORY");
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 TagLib::ID3v2::UnsynchronizedLyricsFrame* frame = new TagLib::ID3v2::UnsynchronizedLyricsFrame;
411 metadata_editor_retvm_if(frame == NULL, METADATA_EDITOR_ERROR_OUT_OF_MEMORY, "OUT_OF_MEMORY");
413 frame->setTextEncoding(TagLib::String::UTF8);
414 frame->setText(TagLib::String(value, TagLib::String::UTF8));
415 tag2->addFrame(frame);
416 } else { // the lyrics frames exist - change the existing one
417 metadata_editor_info("USLT frames exist in file. Changing");
418 TagLib::ID3v2::FrameList::Iterator it = lst.begin();
419 TagLib::ID3v2::UnsynchronizedLyricsFrame* frame = static_cast<TagLib::ID3v2::UnsynchronizedLyricsFrame*>(*it);
420 frame->setTextEncoding(TagLib::String::UTF8);
421 frame->setText(TagLib::String(value, TagLib::String::UTF8));
424 return METADATA_EDITOR_ERROR_NONE;
427 // *** This function extracts string values from tag in MP4 file *** //
428 static int __MP4_getStringItem(metadata_editor_s* _metadata, const char* itemname, char **value) {
429 int ret = METADATA_EDITOR_ERROR_NONE;
431 ret = __check_metadata_get_parameter(_metadata, value);
432 metadata_editor_retvm_if(ret != METADATA_EDITOR_ERROR_NONE, ret, "fail to __check_metadata_get_parameter() [%d]", ret);
433 metadata_editor_retvm_if(!itemname, METADATA_EDITOR_ERROR_INVALID_PARAMETER, "Invalid itemname");
435 TagLib::MP4::File* _file = (TagLib::MP4::File*) _metadata->file;
436 TagLib::MP4::Tag* tag = _file->tag();
437 metadata_editor_retvm_if(tag == NULL, METADATA_EDITOR_ERROR_OPERATION_FAILED, "Tag does not exist");
439 // Get map of items directly from tag and launch a search of specific item
440 TagLib::MP4::ItemListMap& itemMap = tag->itemListMap();
441 TagLib::MP4::ItemListMap::ConstIterator it = itemMap.find(itemname);
442 if (it != itemMap.end()) { // Item was found
443 TagLib::String str = it->second.toStringList()[0]; // Get the first string in item
444 // Check the encoding of the string (1252 or not)
446 if (!str.isLatin1()) isUTF = true;
447 metadata_editor_info("String is %sUTF", (isUTF ? "" : "not "));
448 // Get the length of the string and check if it is empty or not
449 uint length = strlen(str.toCString(isUTF));
450 metadata_editor_retvm_if(length == 0, METADATA_EDITOR_ERROR_NONE, "Empty string");
451 *value = strndup(str.toCString(isUTF), length);
452 return METADATA_EDITOR_ERROR_NONE;
453 } else { // Item was not found
454 metadata_editor_info("No item <%s> in file", itemname);
455 return METADATA_EDITOR_ERROR_NONE;
459 // *** This function extracts integer value from item in MP4 tag *** //
460 static int __MP4_getIntegerItem(metadata_editor_s* _metadata, const char* itemname, char** value) {
461 int ret = METADATA_EDITOR_ERROR_NONE;
463 ret = __check_metadata_get_parameter(_metadata, value);
464 metadata_editor_retvm_if(ret != METADATA_EDITOR_ERROR_NONE, ret, "fail to __check_metadata_get_parameter() [%d]", ret);
465 metadata_editor_retvm_if(!itemname, METADATA_EDITOR_ERROR_INVALID_PARAMETER, "Invalid itemname");
467 TagLib::MP4::File* _file = (TagLib::MP4::File*) _metadata->file;
468 TagLib::MP4::Tag* tag = _file->tag();
469 metadata_editor_retvm_if(tag == NULL, METADATA_EDITOR_ERROR_OPERATION_FAILED, "Tag does not exist");
471 // Get map of items directly from tag and launch a search of specific item
472 TagLib::MP4::ItemListMap& itemMap = tag->itemListMap();
473 TagLib::MP4::ItemListMap::ConstIterator it = itemMap.find(itemname);
474 if (it != itemMap.end()) { // Item was found
475 char buf[META_MAX_BUF_LEN] = {0, };
476 int num = it->second.toInt(); // Get integer value in item
477 snprintf(buf, META_MAX_BUF_LEN, "%u", num); // Convert int into char[]
478 // Determine the length of created c-string and copy it into the output variable
479 int length = strlen(buf);
480 metadata_editor_retvm_if(length == 0, METADATA_EDITOR_ERROR_NONE, "Empty string");
481 *value = strndup(buf, length);
482 return METADATA_EDITOR_ERROR_NONE;
483 } else { // Item was not found
484 metadata_editor_info("No item <%s> in file", itemname);
485 return METADATA_EDITOR_ERROR_NONE;
489 // *** This function adds (or changes) string item of itemname type *** //
490 static int __MP4_updateStringItem(metadata_editor_s* _metadata, const char* itemname, const char* value) {
491 int ret = METADATA_EDITOR_ERROR_NONE;
493 ret = __check_metadata_set_parameter(_metadata);
494 metadata_editor_retvm_if(ret != METADATA_EDITOR_ERROR_NONE, ret, "fail to __check_metadata_set_parameter() [%d]", ret);
495 metadata_editor_retvm_if(!itemname, METADATA_EDITOR_ERROR_INVALID_PARAMETER, "Invalid itemname");
497 TagLib::MP4::File* _file = (TagLib::MP4::File*) _metadata->file;
498 TagLib::MP4::Tag* tag = _file->tag();
499 metadata_editor_retvm_if(tag == NULL, METADATA_EDITOR_ERROR_OPERATION_FAILED, "Tag was not created");
501 // Get map of items directly from tag and launch a search of specific item
502 TagLib::MP4::ItemListMap& itemMap = tag->itemListMap();
503 // Check if it is a request for deletion
504 if ((value == NULL) || value[0] == '\0') {
505 metadata_editor_info("Request for deleting of item <%s>", itemname);
506 TagLib::MP4::ItemListMap::Iterator it = itemMap.find(itemname);
507 if (it != itemMap.end())
509 return METADATA_EDITOR_ERROR_NONE;
511 metadata_editor_info("The item <%s> will be added", itemname);
512 itemMap[itemname] = TagLib::MP4::Item(TagLib::String(value, TagLib::String::UTF8));
514 return METADATA_EDITOR_ERROR_NONE;
517 // *** This function adds (or changes) integer item of itemname type *** //
518 static int __MP4_updateIntegerItem(metadata_editor_s* _metadata, const char* itemname, const char* value) {
519 int ret = METADATA_EDITOR_ERROR_NONE;
521 ret = __check_metadata_set_parameter(_metadata);
522 metadata_editor_retvm_if(ret != METADATA_EDITOR_ERROR_NONE, ret, "fail to __check_metadata_set_parameter() [%d]", ret);
523 metadata_editor_retvm_if(!itemname, METADATA_EDITOR_ERROR_INVALID_PARAMETER, "Invalid itemname");
525 TagLib::MP4::File* _file = (TagLib::MP4::File*) _metadata->file;
526 TagLib::MP4::Tag* tag = _file->tag();
527 metadata_editor_retvm_if(tag == NULL, METADATA_EDITOR_ERROR_OPERATION_FAILED, "Tag was not created");
529 // Get map of items directly from tag and launch a search of specific item
530 TagLib::MP4::ItemListMap& itemMap = tag->itemListMap();
531 // Check if it is a request for deletion
532 if ((value == NULL) || value[0] == '\0') {
533 metadata_editor_info("Request for deleting of item <%s>", itemname);
534 TagLib::MP4::ItemListMap::Iterator it = itemMap.find(itemname);
535 if (it != itemMap.end())
537 return METADATA_EDITOR_ERROR_NONE;
539 // Check if the value is integer string then it can be successfully converted into integer
540 if (isdigit(value[0])) {
541 metadata_editor_info("The item <%s> will be added", itemname);
542 int number = atoi(value);
543 itemMap[itemname] = TagLib::MP4::Item(number);
544 return METADATA_EDITOR_ERROR_NONE;
545 } else { // Notify that string is not a number to process
546 metadata_editor_error("Error. String does not contain a number");
547 return METADATA_EDITOR_ERROR_INVALID_PARAMETER;
551 // *** This function is used to find the number of pictures stored in MP4 file *** //
552 static int __MP4_getNumberOfPictures(metadata_editor_s* _metadata, char** value) {
553 int ret = METADATA_EDITOR_ERROR_NONE;
555 ret = __check_metadata_get_parameter(_metadata, value);
556 metadata_editor_retvm_if(ret != METADATA_EDITOR_ERROR_NONE, ret, "fail to __check_metadata_get_parameter() [%d]", ret);
558 TagLib::MP4::File* _file = (TagLib::MP4::File*) _metadata->file;
559 TagLib::MP4::Tag* tag = _file->tag();
560 metadata_editor_retvm_if(tag == NULL, METADATA_EDITOR_ERROR_OPERATION_FAILED, "Tag does not exist");
562 // Get map of items directly from tag and launch a search of specific item
563 TagLib::MP4::ItemListMap& itemMap = tag->itemListMap();
564 TagLib::MP4::ItemListMap::ConstIterator it = itemMap.find("covr");
565 if (it != itemMap.end()) { // Item was found
566 char buf[META_MAX_BUF_LEN] = {0, };
567 snprintf(buf, META_MAX_BUF_LEN, "%u", it->second.toCoverArtList().size()); // Convert integer value of size to its c-string representation
569 *value = g_strdup(buf);
570 return METADATA_EDITOR_ERROR_NONE;
571 } else { // Item was not found
572 metadata_editor_info("No item <covr> in file");
573 return METADATA_EDITOR_ERROR_NONE;
577 // *** This function is used to extract string from Xiph Comment field *** //
578 static int __xiph_getFieldValue(metadata_editor_s* _metadata, TagLib::Ogg::XiphComment* xtag, const char* fieldname, char** value) {
579 int ret = METADATA_EDITOR_ERROR_NONE;
581 ret = __check_metadata_get_parameter(_metadata, value);
582 metadata_editor_retvm_if(ret != METADATA_EDITOR_ERROR_NONE, ret, "fail to __check_metadata_get_parameter() [%d]", ret);
583 metadata_editor_retvm_if(!fieldname, METADATA_EDITOR_ERROR_INVALID_PARAMETER, "Invalid fieldname");
584 metadata_editor_retvm_if(!xtag, METADATA_EDITOR_ERROR_OPERATION_FAILED, "Tag does not exist");
586 const TagLib::Ogg::FieldListMap& fieldMap = xtag->fieldListMap();
587 TagLib::Ogg::FieldListMap::ConstIterator it = fieldMap.find(fieldname);
589 if ((xtag->contains(fieldname)) && (it != fieldMap.end())) { // Field was found
590 metadata_editor_info("Field %s was found. Extracting", fieldname);
591 TagLib::String str = it->second[0]; // Get the first string in xiph field
592 // Check the encoding of the string (1252 or not)
594 if (!str.isLatin1()) isUTF = true;
595 metadata_editor_info("String is %sUTF", (isUTF ? "" : "not "));
596 // Get the length of the string and check if it is empty or not
597 uint length = strlen(str.toCString(isUTF));
598 metadata_editor_retvm_if(length == 0, METADATA_EDITOR_ERROR_NONE, "Empty string");
599 *value = strndup(str.toCString(isUTF), length);
600 return METADATA_EDITOR_ERROR_NONE;
601 } else { // Field was not found
602 metadata_editor_info("No field %s in Xiph Comment", fieldname);
603 return METADATA_EDITOR_ERROR_NONE;
607 // *** This function is used to write string into Xiph Comment fields *** //
608 static int __xiph_updateFieldValue(metadata_editor_s* _metadata, TagLib::Ogg::XiphComment* xtag, const char* fieldname, const char* value) {
609 int ret = METADATA_EDITOR_ERROR_NONE;
611 ret = __check_metadata_set_parameter(_metadata);
612 metadata_editor_retvm_if(ret != METADATA_EDITOR_ERROR_NONE, ret, "fail to __check_metadata_set_parameter() [%d]", ret);
613 metadata_editor_retvm_if(!fieldname, METADATA_EDITOR_ERROR_INVALID_PARAMETER, "Invalid fieldname");
614 metadata_editor_retvm_if(!xtag, METADATA_EDITOR_ERROR_OPERATION_FAILED, "Tag does not exist");
616 // Check if it is a request for deletion
617 if ((value == NULL) || value[0] == '\0') {
618 metadata_editor_info("Request for deleting of field %s", fieldname);
619 xtag->removeField(fieldname);
620 return METADATA_EDITOR_ERROR_NONE;
622 metadata_editor_info("The field %s will be added", fieldname);
623 // "true" is used to remove other strings of the same "fieldname" first
624 xtag->addField(fieldname, TagLib::String(value, TagLib::String::UTF8), true);
625 return METADATA_EDITOR_ERROR_NONE;
628 // *** This function is used to receive the number of pictures in FLAC file *** //
629 static int __FLAC_getNumberOfPictures(metadata_editor_s* _metadata, char** value) {
630 int ret = METADATA_EDITOR_ERROR_NONE;
632 ret = __check_metadata_get_parameter(_metadata, value);
633 metadata_editor_retvm_if(ret != METADATA_EDITOR_ERROR_NONE, ret, "fail to __check_metadata_get_parameter() [%d]", ret);
635 TagLib::FLAC::File* _file = (TagLib::FLAC::File*) _metadata->file;
636 if (_file->pictureList().isEmpty()) {
637 metadata_editor_info("No pictures in FLAC file");
638 return METADATA_EDITOR_ERROR_NONE;
640 uint number = _file->pictureList().size();
641 metadata_editor_info("There are %u picture(s) in file", number);
642 char buf[META_MAX_BUF_LEN] = {0, };
643 snprintf(buf, META_MAX_BUF_LEN, "%u", number); // Convert integer value of size to its c-string representation
644 uint length = strlen(buf);
645 metadata_editor_retvm_if(length == 0, METADATA_EDITOR_ERROR_NONE, "Empty string");
646 *value = strndup(buf, length);
647 return METADATA_EDITOR_ERROR_NONE;
650 int __metadata_editor_get_file_ext(const char *file_path, char *file_ext, int max_len) {
652 unsigned int path_len = strlen(file_path);
654 for (i = (int)path_len; i >= 0; i--) {
655 if ((file_path[i] == '.') && (i < (int)path_len)) {
656 strncpy(file_ext, &file_path[i + 1], max_len);
660 /* meet the dir. no ext */
661 if (file_path[i] == '/')
668 int __metadata_editor_get_file_type(const char *path) {
670 char mimetype[255] = {0, };
672 /* get content type and mime type from file. */
673 ret = aul_get_mime_from_file(path, mimetype, sizeof(mimetype));
675 metadata_editor_debug("aul_get_mime_from_file fail.. Now trying to get type by extension");
677 char ext[255] = { 0 };
678 int ret = __metadata_editor_get_file_ext(path, ext, sizeof(ext));
679 metadata_editor_retvm_if(ret < 0, METADATA_EDITOR_FORMAT_NOTYPE, "__metadata_editor_get_file_ext failed");
681 if (strcasecmp(ext, "MP3") == 0)
682 return METADATA_EDITOR_FORMAT_MP3;
683 else if (strcasecmp(ext, "MP4") == 0)
684 return METADATA_EDITOR_FORMAT_MP4;
686 return METADATA_EDITOR_FORMAT_NOTYPE;
689 metadata_editor_debug("mime type : %s", mimetype);
691 /* categorize from mimetype */
692 if (strstr(mimetype, "mpeg") != NULL)
693 return METADATA_EDITOR_FORMAT_MP3;
694 else if (strstr(mimetype, "mp4") != NULL)
695 return METADATA_EDITOR_FORMAT_MP4;
697 return METADATA_EDITOR_FORMAT_NOTYPE;
700 int __metadata_editor_get_picture_type(const char *path, char **type) {
702 char mimetype[255] = {0, };
703 const char *type_jpeg = "image/jpeg";
704 const char *type_png = "image/png";
706 /* get content type and mime type from file. */
707 ret = aul_get_mime_from_file(path, mimetype, sizeof(mimetype));
709 metadata_editor_debug("aul_get_mime_from_file fail.. Now trying to get type by extension");
711 char ext[255] = { 0 };
712 int ret = __metadata_editor_get_file_ext(path, ext, sizeof(ext));
713 metadata_editor_retvm_if(ret < 0, METADATA_EDITOR_ERROR_OPERATION_FAILED, "__metadata_editor_get_file_ext failed");
715 if (strcasecmp(ext, "JPG") == 0 || strcasecmp(ext, "JPEG") == 0) {
716 *type = strndup(type_jpeg, strlen(type_jpeg));
717 return METADATA_EDITOR_ERROR_NONE;
718 } else if (strcasecmp(ext, "PNG") == 0) {
719 *type = strndup(type_png, strlen(type_png));
720 return METADATA_EDITOR_ERROR_NONE;
722 return METADATA_EDITOR_ERROR_NOT_SUPPORTED;
726 metadata_editor_debug("mime type : %s", mimetype);
728 /* categorize from mimetype */
729 if (strstr(mimetype, "jpeg") != NULL) {
730 *type = strndup(mimetype, strlen(mimetype));
731 return METADATA_EDITOR_ERROR_NONE;
732 } else if (strstr(mimetype, "png") != NULL) {
733 *type = strndup(mimetype, strlen(mimetype));
734 return METADATA_EDITOR_ERROR_NONE;
737 return METADATA_EDITOR_ERROR_NOT_SUPPORTED;
740 int __metadata_editor_get_picture_info(const char *path, void **picture, int *size, char **type) {
743 ret = __metadata_editor_get_picture_type(path, type);
744 if (ret != METADATA_EDITOR_ERROR_NONE)
745 return METADATA_EDITOR_ERROR_OPERATION_FAILED;
748 FILE* fin = fopen(path, "rb");
749 size_t file_size = 0;
752 while (fgetc(fin) != EOF)
756 char picture_buffer[file_size] = {0, };
757 memset(picture_buffer, 0, file_size * sizeof(char));
758 fin = fopen(path, "rb");
760 if(file_size != fread(picture_buffer, 1, file_size, fin)) {
761 metadata_editor_error("fread error");
763 return METADATA_EDITOR_ERROR_OPERATION_FAILED;
767 if (*picture == NULL) {
768 *picture = malloc(file_size * sizeof(char));
769 memset(*picture, 0, file_size * sizeof(char));
770 memcpy(*picture, picture_buffer, file_size);
775 return METADATA_EDITOR_ERROR_NONE;
778 // *** This function is used to allocate the metadata_editor_s in memory *** //
779 // *** The structure metadata_editor_s contains all information about the file *** //
780 extern "C" int metadata_editor_create(metadata_editor_h *metadata) {
781 metadata_editor_retvm_if(metadata == NULL, METADATA_EDITOR_ERROR_INVALID_PARAMETER, "Invalid metadata");
783 metadata_editor_s *_metadata = new metadata_editor_s; // Allocate a structure for handler
784 metadata_editor_retvm_if(_metadata == NULL, METADATA_EDITOR_ERROR_OUT_OF_MEMORY, "OUT_OF_MEMORY");
786 _metadata->file = NULL;
787 _metadata->filetype = METADATA_EDITOR_FORMAT_NOTYPE; // Specify file type out of range
788 _metadata->isOpen = false; // File is not opened yet
789 _metadata->isReadOnly = true; // Handle unexisting file as readonly
791 // Save the structure in the metadata
792 *metadata = (metadata_editor_h)_metadata;
794 return METADATA_EDITOR_ERROR_NONE;
797 // *** This function is used to open the file. It creates the instance that is responsible for connection with file *** //
798 extern "C" int metadata_editor_set_path(metadata_editor_h metadata, const char *path) {
799 // Check if we have valid arguments to work with
800 metadata_editor_retvm_if(!metadata, METADATA_EDITOR_ERROR_INVALID_PARAMETER, "Invalid metadata");
801 metadata_editor_retvm_if(!path, METADATA_EDITOR_ERROR_INVALID_PARAMETER, "Invalid path");
805 /* check the file exits actually */
806 exist = open(path, O_RDONLY);
808 if (errno == EACCES || errno == EPERM) {
809 metadata_editor_error("Permission denied");
810 return METADATA_EDITOR_ERROR_PERMISSION_DENIED;
812 metadata_editor_error("Not exist file");
813 return METADATA_EDITOR_ERROR_FILE_EXISTS;
819 metadata_editor_s *_metadata = (metadata_editor_s*)metadata;
820 int media_type = METADATA_EDITOR_FORMAT_NOTYPE;
822 media_type = __metadata_editor_get_file_type(path);
824 switch (media_type) { // Parse file according the specified type
825 case METADATA_EDITOR_FORMAT_MP3: {
826 if (_metadata->file) {
827 TagLib::MPEG::File* _file = (TagLib::MPEG::File*)_metadata->file;
828 metadata_editor_info("file free [%p]", _metadata->file);
830 _metadata->file = NULL;
831 _metadata->filetype = METADATA_EDITOR_FORMAT_NOTYPE;
832 _metadata->isOpen = false;
833 _metadata->isReadOnly = true;
836 // Allocate the file object in memory to work with it later on
837 TagLib::MPEG::File* _file = new TagLib::MPEG::File(path);
839 metadata_editor_retvm_if(_file == NULL, METADATA_EDITOR_ERROR_OUT_OF_MEMORY, "OUT_OF_MEMORY");
841 _metadata->file = _file; // Copy file pointer to the structure
843 _metadata->filetype = METADATA_EDITOR_FORMAT_MP3;
845 if (_file->isOpen()) { // Check if the file was opened successfully
846 metadata_editor_info("The file is successfully opened. Address is %p", _metadata->file);
847 _metadata->isOpen = true;
848 } else { // The file does not exist or you have no permission to process it
849 metadata_editor_error("The file was not found. Pointer address is %p", _metadata->file);
850 _metadata->isOpen = false;
851 return METADATA_EDITOR_ERROR_PERMISSION_DENIED;
854 if (_file->readOnly()) { // Check if the file is readonly
855 metadata_editor_info("File is readonly");
856 _metadata->isReadOnly = true;
858 metadata_editor_info("The file is writable");
859 _metadata->isReadOnly = false;
862 return METADATA_EDITOR_ERROR_NONE;
864 case METADATA_EDITOR_FORMAT_MP4: {
865 if (_metadata->file) {
866 TagLib::MP4::File* _file = (TagLib::MP4::File*)_metadata->file;
867 metadata_editor_info("file free [%p]", _metadata->file);
869 _metadata->file = NULL;
870 _metadata->filetype = METADATA_EDITOR_FORMAT_NOTYPE;
871 _metadata->isOpen = false;
872 _metadata->isReadOnly = true;
875 // Allocate the file object in memory to work with it later on
876 TagLib::MP4::File* _file = new TagLib::MP4::File(path);
878 metadata_editor_retvm_if(_file == NULL, METADATA_EDITOR_ERROR_OUT_OF_MEMORY, "OUT_OF_MEMORY");
880 _metadata->file = _file; // Copy file pointer to the structure
882 _metadata->filetype = METADATA_EDITOR_FORMAT_MP4;
884 if (_file->isOpen()) { // Check if the file was opened successfully
885 metadata_editor_info("The file is successfully opened. Address is %p", _metadata->file);
886 _metadata->isOpen = true;
887 } else { // The file does not exist or you have no permission to process it
888 metadata_editor_error("The file was not found. Pointer address is %p", _metadata->file);
889 _metadata->isOpen = false;
890 return METADATA_EDITOR_ERROR_FILE_EXISTS;
892 if (_file->readOnly()) { // Check if the file is readonly
893 metadata_editor_info("File is readonly");
894 _metadata->isReadOnly = true;
896 metadata_editor_info("The file is writable");
897 _metadata->isReadOnly = false;
899 return METADATA_EDITOR_ERROR_NONE;
902 case METADATA_EDITOR_FORMAT_FLAC: {
903 // Allocate the file object in memory to work with it later on
904 TagLib::FLAC::File* _file = new TagLib::FLAC::File(path);
906 metadata_editor_retvm_if(_file == NULL, METADATA_EDITOR_ERROR_OUT_OF_MEMORY, "OUT_OF_MEMORY");
908 _metadata->file = _file; // Copy file pointer to the structure
910 _metadata->filetype = METADATA_EDITOR_FORMAT_FLAC;
912 if (_file->isOpen()) { // Check if the file was opened successfully
913 metadata_editor_info("The file is successfully opened. Address is %p", _metadata->file);
914 _metadata->isOpen = true;
915 } else { // The file does not exist or you have no permission to process it
916 metadata_editor_error("The file was not found. Pointer address is %p", _metadata->file);
917 _metadata->isOpen = false;
918 return METADATA_EDITOR_ERROR_FILE_EXISTS;
920 if (_file->readOnly()) { // Check if the file is readonly
921 metadata_editor_info("File is readonly");
922 _metadata->isReadOnly = true;
924 metadata_editor_info("The file is writable");
925 _metadata->isReadOnly = false;
927 return METADATA_EDITOR_ERROR_NONE;
929 case METADATA_EDITOR_FORMAT_OGG_VORBIS: {
930 // Allocate the file object in memory to work with it later on
931 TagLib::Ogg::Vorbis::File* _file = new TagLib::Ogg::Vorbis::File(path);
933 metadata_editor_retvm_if(_file == NULL, METADATA_EDITOR_ERROR_OUT_OF_MEMORY, "OUT_OF_MEMORY");
935 _metadata->file = _file; // Copy file pointer to the structure
937 _metadata->filetype = METADATA_EDITOR_FORMAT_OGG_VORBIS;
939 if (_file->isOpen()) { // Check if the file was opened successfully
940 metadata_editor_info("The file is successfully opened. Address is %p", _metadata->file);
941 _metadata->isOpen = true;
942 } else { // The file does not exist or you have no permission to process it
943 metadata_editor_error("The file was not found. Pointer address is %p", _metadata->file);
944 _metadata->isOpen = false;
945 return METADATA_EDITOR_ERROR_FILE_EXISTS;
947 if (_file->readOnly()) { // Check if the file is readonly
948 metadata_editor_info("File is readonly");
949 _metadata->isReadOnly = true;
951 metadata_editor_info("The file is writable");
952 _metadata->isReadOnly = false;
954 return METADATA_EDITOR_ERROR_NONE;
956 case METADATA_EDITOR_FORMAT_OGG_FLAC: {
957 // Allocate the file object in memory to work with it later on
958 TagLib::Ogg::FLAC::File* _file = new TagLib::Ogg::FLAC::File(path);
960 metadata_editor_retvm_if(_file == NULL, METADATA_EDITOR_ERROR_OUT_OF_MEMORY, "OUT_OF_MEMORY");
962 _metadata->file = _file; // Copy file pointer to the structure
964 _metadata->filetype = METADATA_EDITOR_FORMAT_OGG_FLAC;
966 if (_file->isOpen()) { // Check if the file was opened successfully
967 metadata_editor_info("The file is successfully opened. Address is %p", _metadata->file);
968 _metadata->isOpen = true;
969 } else { // The file does not exist or you have no permission to process it
970 metadata_editor_error("The file was not found. Pointer address is %p", _metadata->file);
971 _metadata->isOpen = false;
972 return METADATA_EDITOR_ERROR_FILE_EXISTS;
974 if (_file->readOnly()) { // Check if the file is readonly
975 metadata_editor_info("File is readonly");
976 _metadata->isReadOnly = true;
978 metadata_editor_info("The file is writable");
979 _metadata->isReadOnly = false;
981 return METADATA_EDITOR_ERROR_NONE;
983 case METADATA_EDITOR_FORMAT_WAV: {
984 // Allocate the file object in memory to work with it later on
985 TagLib::RIFF::WAV::File* _file = new TagLib::RIFF::WAV::File(path);
987 metadata_editor_retvm_if(_file == NULL, METADATA_EDITOR_ERROR_OUT_OF_MEMORY, "OUT_OF_MEMORY");
989 _metadata->file = _file; // Copy file pointer to the structure
991 _metadata->filetype = METADATA_EDITOR_FORMAT_WAV;
993 if (_file->isOpen()) { // Check if the file was opened successfully
994 metadata_editor_info("The file is successfully opened. Address is %p", _metadata->file);
995 _metadata->isOpen = true;
996 } else { // The file does not exist or you have no permission to process it
997 metadata_editor_error("The file was not found. Pointer address is %p", _metadata->file);
998 _metadata->isOpen = false;
999 return METADATA_EDITOR_ERROR_FILE_EXISTS;
1001 if (_file->readOnly()) { // Check if the file is readonly
1002 metadata_editor_info("File is readonly");
1003 _metadata->isReadOnly = true;
1005 metadata_editor_info("The file is writable");
1006 _metadata->isReadOnly = false;
1008 return METADATA_EDITOR_ERROR_NONE;
1012 metadata_editor_error("Wrong file type");
1013 return METADATA_EDITOR_ERROR_NOT_SUPPORTED;
1017 static int __metadata_editor_get_mp3_metadata(metadata_editor_s *metadata, metadata_editor_attr_e attribute, char **value)
1019 int ret = METADATA_EDITOR_ERROR_NONE;
1021 ret = __check_metadata_get_parameter(metadata, value);
1022 metadata_editor_retvm_if(ret != METADATA_EDITOR_ERROR_NONE, ret, "fail to __check_metadata_get_parameter() [%d]", ret);
1024 // Bring the pointer to actual file type and make tag pointers
1025 TagLib::MPEG::File* _file = (TagLib::MPEG::File*)metadata->file;
1026 TagLib::ID3v1::Tag* tag1 = _file->ID3v1Tag();
1027 TagLib::ID3v2::Tag* tag2 = _file->ID3v2Tag();
1029 switch (attribute) { // Check which one of frame types was given to the function for processing
1030 case METADATA_EDITOR_ATTR_ARTIST: return __ID3_getTwixFrameByName(metadata, tag1, tag2, "TPE1", value);
1031 case METADATA_EDITOR_ATTR_TITLE: return __ID3_getTwixFrameByName(metadata, tag1, tag2, "TIT2", value);
1032 case METADATA_EDITOR_ATTR_ALBUM: return __ID3_getTwixFrameByName(metadata, tag1, tag2, "TALB", value);
1033 case METADATA_EDITOR_ATTR_GENRE: return __ID3_getTwixFrameByName(metadata, tag1, tag2, "TCON", value);
1034 case METADATA_EDITOR_ATTR_AUTHOR: return __ID3_getFrameByName(metadata, tag2, "TCOM", value);
1035 case METADATA_EDITOR_ATTR_COPYRIGHT: return __ID3_getFrameByName(metadata, tag2, "TCOP", value);
1036 case METADATA_EDITOR_ATTR_DATE: return __ID3_getTwixFrameByName(metadata, tag1, tag2, "TDRC", value);
1037 case METADATA_EDITOR_ATTR_DESCRIPTION: return __ID3_getFrameByName(metadata, tag2, "TIT3", value);
1038 case METADATA_EDITOR_ATTR_COMMENT: return __ID3_getTwixFrameByName(metadata, tag1, tag2, "COMM", value);
1039 case METADATA_EDITOR_ATTR_TRACK_NUM: return __ID3_getTwixFrameByName(metadata, tag1, tag2, "TRCK", value);
1040 case METADATA_EDITOR_ATTR_CONDUCTOR: return __ID3_getFrameByName(metadata, tag2, "TPE3", value);
1041 case METADATA_EDITOR_ATTR_PICTURE_NUM: return __ID3_getNumberOfPictures(metadata, tag2, value);
1042 case METADATA_EDITOR_ATTR_UNSYNCLYRICS: return __ID3_getLyricsFrame(metadata, tag2, value);
1044 return METADATA_EDITOR_ERROR_INVALID_PARAMETER;
1048 static int __metadata_editor_get_mp4_metadata(metadata_editor_s *metadata, metadata_editor_attr_e attribute, char **value)
1050 int ret = METADATA_EDITOR_ERROR_NONE;
1052 ret = __check_metadata_get_parameter(metadata, value);
1053 metadata_editor_retvm_if(ret != METADATA_EDITOR_ERROR_NONE, ret, "fail to __check_metadata_get_parameter() [%d]", ret);
1055 switch (attribute) { // Check which one of frame types was given to the function for processing
1056 case METADATA_EDITOR_ATTR_ARTIST: return __MP4_getStringItem(metadata, "\xA9""ART", value);
1057 case METADATA_EDITOR_ATTR_TITLE: return __MP4_getStringItem(metadata, "\xA9""nam", value);
1058 case METADATA_EDITOR_ATTR_ALBUM: return __MP4_getStringItem(metadata, "\xA9""alb", value);
1059 case METADATA_EDITOR_ATTR_GENRE: return __MP4_getStringItem(metadata, "\xA9""gen", value);
1060 case METADATA_EDITOR_ATTR_AUTHOR: return __MP4_getStringItem(metadata, "\xA9""wrt", value);
1061 case METADATA_EDITOR_ATTR_COPYRIGHT: return __MP4_getStringItem(metadata, "cprt", value);
1062 case METADATA_EDITOR_ATTR_DATE: return __MP4_getStringItem(metadata, "\xA9""day", value);
1063 case METADATA_EDITOR_ATTR_DESCRIPTION: return __MP4_getStringItem(metadata, "desc", value);
1064 case METADATA_EDITOR_ATTR_COMMENT: return __MP4_getStringItem(metadata, "\xA9""cmt", value);
1065 case METADATA_EDITOR_ATTR_TRACK_NUM: return __MP4_getIntegerItem(metadata, "trkn", value);
1066 case METADATA_EDITOR_ATTR_CONDUCTOR: return __MP4_getStringItem(metadata, "cond", value);
1067 case METADATA_EDITOR_ATTR_UNSYNCLYRICS: return __MP4_getStringItem(metadata, "\xA9""lyr", value);
1068 case METADATA_EDITOR_ATTR_PICTURE_NUM: return __MP4_getNumberOfPictures(metadata, value);
1070 return METADATA_EDITOR_ERROR_INVALID_PARAMETER;
1075 static int __metadata_editor_get_flac_metadata(metadata_editor_s *metadata, metadata_editor_attr_e attribute, char **value)
1077 int ret = METADATA_EDITOR_ERROR_NONE;
1079 ret = __check_metadata_get_parameter(metadata, value);
1080 metadata_editor_retvm_if(ret != METADATA_EDITOR_ERROR_NONE, ret, "fail to __check_metadata_get_parameter() [%d]", ret);
1082 // Bring the pointer to actual file type and make tags pointers
1083 TagLib::FLAC::File* _file = (TagLib::FLAC::File*)metadata->file;
1084 TagLib::Ogg::XiphComment* xtag = _file->xiphComment(false);
1085 if (!xtag) { // Check if we have a valid tag for processing
1086 metadata_editor_error("Tag does not exist");
1088 return METADATA_EDITOR_ERROR_OPERATION_FAILED;
1090 switch (attribute) { // Check which one of frame types was given to the function for processing
1091 case METADATA_EDITOR_ATTR_ARTIST: return __xiph_getFieldValue(metadata, xtag, "ARTIST", value);
1092 case METADATA_EDITOR_ATTR_TITLE: return __xiph_getFieldValue(metadata, xtag, "TITLE", value);
1093 case METADATA_EDITOR_ATTR_ALBUM: return __xiph_getFieldValue(metadata, xtag, "ALBUM", value);
1094 case METADATA_EDITOR_ATTR_GENRE: return __xiph_getFieldValue(metadata, xtag, "GENRE", value);
1095 case METADATA_EDITOR_ATTR_AUTHOR: return __xiph_getFieldValue(metadata, xtag, "COMPOSER", value);
1096 case METADATA_EDITOR_ATTR_COPYRIGHT: return __xiph_getFieldValue(metadata, xtag, "COPYRIGHT", value);
1097 case METADATA_EDITOR_ATTR_DATE: return __xiph_getFieldValue(metadata, xtag, "DATE", value);
1098 case METADATA_EDITOR_ATTR_DESCRIPTION: return __xiph_getFieldValue(metadata, xtag, "DESCRIPTION", value);
1099 case METADATA_EDITOR_ATTR_COMMENT: return __xiph_getFieldValue(metadata, xtag, "COMMENT", value);
1100 case METADATA_EDITOR_ATTR_TRACK_NUM: return __xiph_getFieldValue(metadata, xtag, "TRACKNUMBER", value);
1101 case METADATA_EDITOR_ATTR_CONDUCTOR: return __xiph_getFieldValue(metadata, xtag, "CONDUCTOR", value);
1102 case METADATA_EDITOR_ATTR_UNSYNCLYRICS: return __xiph_getFieldValue(metadata, xtag, "LYRICS", value);
1103 case METADATA_EDITOR_ATTR_PICTURE_NUM: return __FLAC_getNumberOfPictures(metadata, value);
1105 return METADATA_EDITOR_ERROR_INVALID_PARAMETER;
1109 static int __metadata_editor_get_ogg_vorbis_metadata(metadata_editor_s *metadata, metadata_editor_attr_e attribute, char **value)
1111 int ret = METADATA_EDITOR_ERROR_NONE;
1113 ret = __check_metadata_get_parameter(metadata, value);
1114 metadata_editor_retvm_if(ret != METADATA_EDITOR_ERROR_NONE, ret, "fail to __check_metadata_get_parameter() [%d]", ret);
1116 // Bring the pointer to actual file type and make tags pointers
1117 TagLib::Ogg::Vorbis::File* _file = (TagLib::Ogg::Vorbis::File*)metadata->file;
1118 TagLib::Ogg::XiphComment* xtag = _file->tag();
1119 if (!xtag) { // Check if we have a valid tag for processing
1120 metadata_editor_error("Tag does not exist");
1122 return METADATA_EDITOR_ERROR_OPERATION_FAILED;
1124 switch (attribute) { // Check which one of frame types was given to the function for processing
1125 case METADATA_EDITOR_ATTR_ARTIST: return __xiph_getFieldValue(metadata, xtag, "ARTIST", value);
1126 case METADATA_EDITOR_ATTR_TITLE: return __xiph_getFieldValue(metadata, xtag, "TITLE", value);
1127 case METADATA_EDITOR_ATTR_ALBUM: return __xiph_getFieldValue(metadata, xtag, "ALBUM", value);
1128 case METADATA_EDITOR_ATTR_GENRE: return __xiph_getFieldValue(metadata, xtag, "GENRE", value);
1129 case METADATA_EDITOR_ATTR_AUTHOR: return __xiph_getFieldValue(metadata, xtag, "COMPOSER", value);
1130 case METADATA_EDITOR_ATTR_COPYRIGHT: return __xiph_getFieldValue(metadata, xtag, "COPYRIGHT", value);
1131 case METADATA_EDITOR_ATTR_DATE: return __xiph_getFieldValue(metadata, xtag, "DATE", value);
1132 case METADATA_EDITOR_ATTR_DESCRIPTION: return __xiph_getFieldValue(metadata, xtag, "DESCRIPTION", value);
1133 case METADATA_EDITOR_ATTR_COMMENT: return __xiph_getFieldValue(metadata, xtag, "COMMENT", value);
1134 case METADATA_EDITOR_ATTR_TRACK_NUM: return __xiph_getFieldValue(metadata, xtag, "TRACKNUMBER", value);
1135 case METADATA_EDITOR_ATTR_CONDUCTOR: return __xiph_getFieldValue(metadata, xtag, "CONDUCTOR", value);
1136 case METADATA_EDITOR_ATTR_UNSYNCLYRICS: return __xiph_getFieldValue(metadata, xtag, "LYRICS", value);
1138 return METADATA_EDITOR_ERROR_INVALID_PARAMETER;
1142 static int __metadata_editor_get_ogg_flac_metadata(metadata_editor_s *metadata, metadata_editor_attr_e attribute, char **value)
1144 int ret = METADATA_EDITOR_ERROR_NONE;
1146 ret = __check_metadata_get_parameter(metadata, value);
1147 metadata_editor_retvm_if(ret != METADATA_EDITOR_ERROR_NONE, ret, "fail to __check_metadata_get_parameter() [%d]", ret);
1149 // Bring the pointer to actual file type and make tags pointers
1150 TagLib::Ogg::FLAC::File* _file = (TagLib::Ogg::FLAC::File*)metadata->file;
1151 TagLib::Ogg::XiphComment* xtag = _file->tag();
1152 if (!xtag) { // Check if we have a valid tag for processing
1153 metadata_editor_error("Tag does not exist");
1155 return METADATA_EDITOR_ERROR_OPERATION_FAILED;
1157 switch (attribute) { // Check which one of frame types was given to the function for processing
1158 case METADATA_EDITOR_ATTR_ARTIST: return __xiph_getFieldValue(metadata, xtag, "ARTIST", value);
1159 case METADATA_EDITOR_ATTR_TITLE: return __xiph_getFieldValue(metadata, xtag, "TITLE", value);
1160 case METADATA_EDITOR_ATTR_ALBUM: return __xiph_getFieldValue(metadata, xtag, "ALBUM", value);
1161 case METADATA_EDITOR_ATTR_GENRE: return __xiph_getFieldValue(metadata, xtag, "GENRE", value);
1162 case METADATA_EDITOR_ATTR_AUTHOR: return __xiph_getFieldValue(metadata, xtag, "COMPOSER", value);
1163 case METADATA_EDITOR_ATTR_COPYRIGHT: return __xiph_getFieldValue(metadata, xtag, "COPYRIGHT", value);
1164 case METADATA_EDITOR_ATTR_DATE: return __xiph_getFieldValue(metadata, xtag, "DATE", value);
1165 case METADATA_EDITOR_ATTR_DESCRIPTION: return __xiph_getFieldValue(metadata, xtag, "DESCRIPTION", value);
1166 case METADATA_EDITOR_ATTR_COMMENT: return __xiph_getFieldValue(metadata, xtag, "COMMENT", value);
1167 case METADATA_EDITOR_ATTR_TRACK_NUM: return __xiph_getFieldValue(metadata, xtag, "TRACKNUMBER", value);
1168 case METADATA_EDITOR_ATTR_CONDUCTOR: return __xiph_getFieldValue(metadata, xtag, "CONDUCTOR", value);
1169 case METADATA_EDITOR_ATTR_UNSYNCLYRICS: return __xiph_getFieldValue(metadata, xtag, "LYRICS", value);
1171 return METADATA_EDITOR_ERROR_INVALID_PARAMETER;
1175 static int __metadata_editor_get_wav_metadata(metadata_editor_s *metadata, metadata_editor_attr_e attribute, char **value)
1177 int ret = METADATA_EDITOR_ERROR_NONE;
1179 ret = __check_metadata_get_parameter(metadata, value);
1180 metadata_editor_retvm_if(ret != METADATA_EDITOR_ERROR_NONE, ret, "fail to __check_metadata_get_parameter() [%d]", ret);
1182 // Bring the pointer to actual file type and make tag pointers
1183 TagLib::RIFF::WAV::File* _file = (TagLib::RIFF::WAV::File*)metadata->file;
1184 TagLib::ID3v2::Tag* tag2 = _file->tag();
1186 if (tag2 == NULL) { // Check if we have a valid tag for processing
1187 metadata_editor_error("Error. ID3v2 tag does not exist. Can not proceed metadata extraction");
1189 return METADATA_EDITOR_ERROR_OPERATION_FAILED;
1192 switch (attribute) { // Check which one of frame types was given to the function for processing
1193 case METADATA_EDITOR_ATTR_ARTIST: return __ID3_getFrameByName(metadata, tag2, "TPE1", value);
1194 case METADATA_EDITOR_ATTR_TITLE: return __ID3_getFrameByName(metadata, tag2, "TIT2", value);
1195 case METADATA_EDITOR_ATTR_ALBUM: return __ID3_getFrameByName(metadata, tag2, "TALB", value);
1196 case METADATA_EDITOR_ATTR_GENRE: return __ID3_getFrameByName(metadata, tag2, "TCON", value);
1197 case METADATA_EDITOR_ATTR_AUTHOR: return __ID3_getFrameByName(metadata, tag2, "TCOM", value);
1198 case METADATA_EDITOR_ATTR_COPYRIGHT: return __ID3_getFrameByName(metadata, tag2, "TCOP", value);
1199 case METADATA_EDITOR_ATTR_DATE: return __ID3_getFrameByName(metadata, tag2, "TDRC", value);
1200 case METADATA_EDITOR_ATTR_DESCRIPTION: return __ID3_getFrameByName(metadata, tag2, "TIT3", value);
1201 case METADATA_EDITOR_ATTR_COMMENT: return __ID3_getFrameByName(metadata, tag2, "COMM", value);
1202 case METADATA_EDITOR_ATTR_TRACK_NUM: return __ID3_getFrameByName(metadata, tag2, "TRCK", value);
1203 case METADATA_EDITOR_ATTR_CONDUCTOR: return __ID3_getFrameByName(metadata, tag2, "TPE3", value);
1204 case METADATA_EDITOR_ATTR_PICTURE_NUM: return __ID3_getNumberOfPictures(metadata, tag2, value);
1205 case METADATA_EDITOR_ATTR_UNSYNCLYRICS: return __ID3_getLyricsFrame(metadata, tag2, value);
1207 return METADATA_EDITOR_ERROR_INVALID_PARAMETER;
1212 // *** This function is used to get the tag frame (field, item - each tag has its own name for data unit) from file *** //
1213 extern "C" int metadata_editor_get_metadata(metadata_editor_h metadata, metadata_editor_attr_e attribute, char **value) {
1215 metadata_editor_s *_metadata = (metadata_editor_s*)metadata;
1216 metadata_editor_retvm_if(!_metadata, METADATA_EDITOR_ERROR_INVALID_PARAMETER, "Invalid metadata");
1218 switch (_metadata->filetype) { // Process the file according to the specified file type
1219 case METADATA_EDITOR_FORMAT_MP3:
1220 return __metadata_editor_get_mp3_metadata(_metadata, attribute, value);
1222 case METADATA_EDITOR_FORMAT_MP4:
1223 return __metadata_editor_get_mp4_metadata(_metadata, attribute, value);
1226 case METADATA_EDITOR_FORMAT_FLAC: {
1227 return __metadata_editor_get_flac_metadata(_metadata, attribute, value);
1229 case METADATA_EDITOR_FORMAT_OGG_VORBIS: {
1230 return __metadata_editor_get_ogg_vorbis_metadata(_metadata, attribute, value);
1232 case METADATA_EDITOR_FORMAT_OGG_FLAC: {
1233 return __metadata_editor_get_ogg_flac_metadata(_metadata, attribute, value);
1235 case METADATA_EDITOR_FORMAT_WAV: {
1236 return __metadata_editor_get_wav_metadata(_metadata, attribute, value);
1240 metadata_editor_error("Wrong file type [%d]", _metadata->filetype);
1241 return METADATA_EDITOR_ERROR_INVALID_PARAMETER;
1245 static int __metadata_editor_set_mp3_metadata(metadata_editor_s* metadata, metadata_editor_attr_e attribute, const char* value)
1247 int ret = METADATA_EDITOR_ERROR_NONE;
1249 ret = __check_metadata_set_parameter(metadata);
1250 metadata_editor_retvm_if(ret != METADATA_EDITOR_ERROR_NONE, ret, "fail to __check_metadata_set_parameter() [%d]", ret);
1252 // Bring the pointer to actual file type and make tags pointers
1253 TagLib::MPEG::File* _file = (TagLib::MPEG::File*)metadata->file;
1254 TagLib::ID3v1::Tag* tag1 = _file->ID3v1Tag();
1255 TagLib::ID3v2::Tag* tag2 = _file->ID3v2Tag(true);
1257 metadata_editor_retvm_if(tag2 == NULL, METADATA_EDITOR_ERROR_OPERATION_FAILED, "Error. ID3v2 tag was not created. Can not proceed metadata updating");
1259 switch (attribute) { // Check which one of frame type was given for processing
1260 case METADATA_EDITOR_ATTR_ARTIST: return __ID3_setTwixFrameByName(metadata, tag1, tag2, "TPE1", value);
1261 case METADATA_EDITOR_ATTR_TITLE: return __ID3_setTwixFrameByName(metadata, tag1, tag2, "TIT2", value);
1262 case METADATA_EDITOR_ATTR_ALBUM: return __ID3_setTwixFrameByName(metadata, tag1, tag2, "TALB", value);
1263 case METADATA_EDITOR_ATTR_GENRE: return __ID3_setTwixFrameByName(metadata, tag1, tag2, "TCON", value);
1264 case METADATA_EDITOR_ATTR_AUTHOR: return __ID3_setFrameByName(metadata, tag2, "TCOM", value);
1265 case METADATA_EDITOR_ATTR_COPYRIGHT: return __ID3_setFrameByName(metadata, tag2, "TCOP", value);
1266 case METADATA_EDITOR_ATTR_DATE: return __ID3_setTwixFrameByName(metadata, tag1, tag2, "TDRC", value);
1267 case METADATA_EDITOR_ATTR_DESCRIPTION: return __ID3_setFrameByName(metadata, tag2, "TIT3", value);
1268 case METADATA_EDITOR_ATTR_TRACK_NUM: return __ID3_setTwixFrameByName(metadata, tag1, tag2, "TRCK", value);
1269 case METADATA_EDITOR_ATTR_CONDUCTOR: return __ID3_setFrameByName(metadata, tag2, "TPE3", value);
1270 case METADATA_EDITOR_ATTR_COMMENT: return __ID3_setTwixCommentFrame(metadata, tag1, tag2, value);
1271 case METADATA_EDITOR_ATTR_UNSYNCLYRICS: return __ID3_setLyricsFrame(metadata, tag2, value);
1273 return METADATA_EDITOR_ERROR_INVALID_PARAMETER;
1277 static int __metadata_editor_set_mp4_metadata(metadata_editor_s* metadata, metadata_editor_attr_e attribute, const char* value)
1279 int ret = METADATA_EDITOR_ERROR_NONE;
1281 ret = __check_metadata_set_parameter(metadata);
1282 metadata_editor_retvm_if(ret != METADATA_EDITOR_ERROR_NONE, ret, "fail to __check_metadata_set_parameter() [%d]", ret);
1284 switch (attribute) { // Check which one of frame type was given for processing
1285 case METADATA_EDITOR_ATTR_ARTIST: return __MP4_updateStringItem(metadata, "\xA9""ART", value);
1286 case METADATA_EDITOR_ATTR_TITLE: return __MP4_updateStringItem(metadata, "\xA9""nam", value);
1287 case METADATA_EDITOR_ATTR_ALBUM: return __MP4_updateStringItem(metadata, "\xA9""alb", value);
1288 case METADATA_EDITOR_ATTR_GENRE: return __MP4_updateStringItem(metadata, "\xA9""gen", value);
1289 case METADATA_EDITOR_ATTR_AUTHOR: return __MP4_updateStringItem(metadata, "\xA9""wrt", value);
1290 case METADATA_EDITOR_ATTR_COPYRIGHT: return __MP4_updateStringItem(metadata, "cprt", value);
1291 case METADATA_EDITOR_ATTR_DATE: return __MP4_updateStringItem(metadata, "\xA9""day", value);
1292 case METADATA_EDITOR_ATTR_DESCRIPTION: return __MP4_updateStringItem(metadata, "desc", value);
1293 case METADATA_EDITOR_ATTR_COMMENT: return __MP4_updateStringItem(metadata, "\xA9""cmt", value);
1294 case METADATA_EDITOR_ATTR_TRACK_NUM: return __MP4_updateIntegerItem(metadata, "trkn", value);
1295 case METADATA_EDITOR_ATTR_CONDUCTOR: return __MP4_updateStringItem(metadata, "cond", value);
1296 case METADATA_EDITOR_ATTR_UNSYNCLYRICS: return __MP4_updateStringItem(metadata, "\xA9""lyr", value);
1298 return METADATA_EDITOR_ERROR_INVALID_PARAMETER;
1303 static int __metadata_editor_set_flac_metadata(metadata_editor_s* metadata, metadata_editor_attr_e attribute, const char* value)
1305 int ret = METADATA_EDITOR_ERROR_NONE;
1307 ret = __check_metadata_set_parameter(metadata);
1308 metadata_editor_retvm_if(ret != METADATA_EDITOR_ERROR_NONE, ret, "fail to __check_metadata_set_parameter() [%d]", ret);
1310 // Bring the pointer to actual file type and make tags pointers
1311 TagLib::FLAC::File* _file = (TagLib::FLAC::File*)metadata->file;
1312 TagLib::Ogg::XiphComment* xtag = _file->xiphComment(true);
1313 if (!xtag) { // Check if we have a valid tag for processing
1314 metadata_editor_error("Error. Xiph Comment was not created. Can not proceed metadata updating");
1315 return METADATA_EDITOR_ERROR_OPERATION_FAILED;
1317 switch (attribute) { // Check which one of frame type was given for processing
1318 case METADATA_EDITOR_ATTR_ARTIST: return __xiph_updateFieldValue(metadata, xtag, "ARTIST", value);
1319 case METADATA_EDITOR_ATTR_TITLE: return __xiph_updateFieldValue(metadata, xtag, "TITLE", value);
1320 case METADATA_EDITOR_ATTR_ALBUM: return __xiph_updateFieldValue(metadata, xtag, "ALBUM", value);
1321 case METADATA_EDITOR_ATTR_GENRE: return __xiph_updateFieldValue(metadata, xtag, "GENRE", value);
1322 case METADATA_EDITOR_ATTR_AUTHOR: return __xiph_updateFieldValue(metadata, xtag, "COMPOSER", value);
1323 case METADATA_EDITOR_ATTR_COPYRIGHT: return __xiph_updateFieldValue(metadata, xtag, "COPYRIGHT", value);
1324 case METADATA_EDITOR_ATTR_DATE: return __xiph_updateFieldValue(metadata, xtag, "DATE", value);
1325 case METADATA_EDITOR_ATTR_DESCRIPTION: return __xiph_updateFieldValue(metadata, xtag, "DESCRIPTION", value);
1326 case METADATA_EDITOR_ATTR_COMMENT: return __xiph_updateFieldValue(metadata, xtag, "COMMENT", value);
1327 case METADATA_EDITOR_ATTR_TRACK_NUM: return __xiph_updateFieldValue(metadata, xtag, "TRACKNUMBER", value);
1328 case METADATA_EDITOR_ATTR_CONDUCTOR: return __xiph_updateFieldValue(metadata, xtag, "CONDUCTOR", value);
1329 case METADATA_EDITOR_ATTR_UNSYNCLYRICS: return __xiph_updateFieldValue(metadata, xtag, "LYRICS", value);
1331 return METADATA_EDITOR_ERROR_INVALID_PARAMETER;
1335 static int __metadata_editor_set_ogg_vorbis_metadata(metadata_editor_s* metadata, metadata_editor_attr_e attribute, const char* value)
1337 int ret = METADATA_EDITOR_ERROR_NONE;
1339 ret = __check_metadata_set_parameter(metadata);
1340 metadata_editor_retvm_if(ret != METADATA_EDITOR_ERROR_NONE, ret, "fail to __check_metadata_set_parameter() [%d]", ret);
1342 // Bring the pointer to actual file type and make tags pointers
1343 TagLib::Ogg::Vorbis::File* _file = (TagLib::Ogg::Vorbis::File*)metadata->file;
1344 TagLib::Ogg::XiphComment* xtag = _file->tag();
1345 if (!xtag) { // Check if we have a valid tag for processing
1346 metadata_editor_error("Error. Xiph Comment was not created. Can not proceed metadata updating");
1347 return METADATA_EDITOR_ERROR_OPERATION_FAILED;
1349 switch (attribute) { // Check which one of frame type was given for processing
1350 case METADATA_EDITOR_ATTR_ARTIST: return __xiph_updateFieldValue(metadata, xtag, "ARTIST", value);
1351 case METADATA_EDITOR_ATTR_TITLE: return __xiph_updateFieldValue(metadata, xtag, "TITLE", value);
1352 case METADATA_EDITOR_ATTR_ALBUM: return __xiph_updateFieldValue(metadata, xtag, "ALBUM", value);
1353 case METADATA_EDITOR_ATTR_GENRE: return __xiph_updateFieldValue(metadata, xtag, "GENRE", value);
1354 case METADATA_EDITOR_ATTR_AUTHOR: return __xiph_updateFieldValue(metadata, xtag, "COMPOSER", value);
1355 case METADATA_EDITOR_ATTR_COPYRIGHT: return __xiph_updateFieldValue(metadata, xtag, "COPYRIGHT", value);
1356 case METADATA_EDITOR_ATTR_DATE: return __xiph_updateFieldValue(metadata, xtag, "DATE", value);
1357 case METADATA_EDITOR_ATTR_DESCRIPTION: return __xiph_updateFieldValue(metadata, xtag, "DESCRIPTION", value);
1358 case METADATA_EDITOR_ATTR_COMMENT: return __xiph_updateFieldValue(metadata, xtag, "COMMENT", value);
1359 case METADATA_EDITOR_ATTR_TRACK_NUM: return __xiph_updateFieldValue(metadata, xtag, "TRACKNUMBER", value);
1360 case METADATA_EDITOR_ATTR_CONDUCTOR: return __xiph_updateFieldValue(metadata, xtag, "CONDUCTOR", value);
1361 case METADATA_EDITOR_ATTR_UNSYNCLYRICS: return __xiph_updateFieldValue(metadata, xtag, "LYRICS", value);
1363 return METADATA_EDITOR_ERROR_INVALID_PARAMETER;
1367 static int __metadata_editor_set_ogg_flac_metadata(metadata_editor_s* metadata, metadata_editor_attr_e attribute, const char* value)
1369 int ret = METADATA_EDITOR_ERROR_NONE;
1371 ret = __check_metadata_set_parameter(metadata);
1372 metadata_editor_retvm_if(ret != METADATA_EDITOR_ERROR_NONE, ret, "fail to __check_metadata_set_parameter() [%d]", ret);
1374 // Bring the pointer to actual file type and make tags pointers
1375 TagLib::Ogg::FLAC::File* _file = (TagLib::Ogg::FLAC::File*)metadata->file;
1376 TagLib::Ogg::XiphComment* xtag = _file->tag();
1377 if (!xtag) { // Check if we have a valid tag for processing
1378 metadata_editor_error("Error. Xiph Comment was not created. Can not proceed metadata updating");
1379 return METADATA_EDITOR_ERROR_OPERATION_FAILED;
1381 switch (attribute) { // Check which one of frame type was given for processing
1382 case METADATA_EDITOR_ATTR_ARTIST: return __xiph_updateFieldValue(metadata, xtag, "ARTIST", value);
1383 case METADATA_EDITOR_ATTR_TITLE: return __xiph_updateFieldValue(metadata, xtag, "TITLE", value);
1384 case METADATA_EDITOR_ATTR_ALBUM: return __xiph_updateFieldValue(metadata, xtag, "ALBUM", value);
1385 case METADATA_EDITOR_ATTR_GENRE: return __xiph_updateFieldValue(metadata, xtag, "GENRE", value);
1386 case METADATA_EDITOR_ATTR_AUTHOR: return __xiph_updateFieldValue(metadata, xtag, "COMPOSER", value);
1387 case METADATA_EDITOR_ATTR_COPYRIGHT: return __xiph_updateFieldValue(metadata, xtag, "COPYRIGHT", value);
1388 case METADATA_EDITOR_ATTR_DATE: return __xiph_updateFieldValue(metadata, xtag, "DATE", value);
1389 case METADATA_EDITOR_ATTR_DESCRIPTION: return __xiph_updateFieldValue(metadata, xtag, "DESCRIPTION", value);
1390 case METADATA_EDITOR_ATTR_COMMENT: return __xiph_updateFieldValue(metadata, xtag, "COMMENT", value);
1391 case METADATA_EDITOR_ATTR_TRACK_NUM: return __xiph_updateFieldValue(metadata, xtag, "TRACKNUMBER", value);
1392 case METADATA_EDITOR_ATTR_CONDUCTOR: return __xiph_updateFieldValue(metadata, xtag, "CONDUCTOR", value);
1393 case METADATA_EDITOR_ATTR_UNSYNCLYRICS: return __xiph_updateFieldValue(metadata, xtag, "LYRICS", value);
1395 return METADATA_EDITOR_ERROR_INVALID_PARAMETER;
1399 static int __metadata_editor_set_wav_metadata(metadata_editor_s* metadata, metadata_editor_attr_e attribute, const char* value)
1401 int ret = METADATA_EDITOR_ERROR_NONE;
1403 ret = __check_metadata_set_parameter(metadata);
1404 metadata_editor_retvm_if(ret != METADATA_EDITOR_ERROR_NONE, ret, "fail to __check_metadata_set_parameter() [%d]", ret);
1406 // Bring the pointer to actual file type and make tags pointers
1407 TagLib::RIFF::WAV::File* _file = (TagLib::RIFF::WAV::File*)metadata->file;
1408 TagLib::ID3v2::Tag* tag2 = _file->tag();
1409 // Check if the valid tag pointer exist
1411 metadata_editor_error("Error. ID3v2 tag was not created. Can not proceed metadata updating");
1412 return METADATA_EDITOR_ERROR_OPERATION_FAILED;
1415 switch (attribute) { // Check which one of frame type was given for processing
1416 case METADATA_EDITOR_ATTR_ARTIST: return __ID3_setFrameByName(metadata, tag2, "TPE1", value);
1417 case METADATA_EDITOR_ATTR_TITLE: return __ID3_setFrameByName(metadata, tag2, "TIT2", value);
1418 case METADATA_EDITOR_ATTR_ALBUM: return __ID3_setFrameByName(metadata, tag2, "TALB", value);
1419 case METADATA_EDITOR_ATTR_GENRE: return __ID3_setFrameByName(metadata, tag2, "TCON", value);
1420 case METADATA_EDITOR_ATTR_AUTHOR: return __ID3_setFrameByName(metadata, tag2, "TCOM", value);
1421 case METADATA_EDITOR_ATTR_COPYRIGHT: return __ID3_setFrameByName(metadata, tag2, "TCOP", value);
1422 case METADATA_EDITOR_ATTR_DATE: return __ID3_setFrameByName(metadata, tag2, "TDRC", value);
1423 case METADATA_EDITOR_ATTR_DESCRIPTION: return __ID3_setFrameByName(metadata, tag2, "TIT3", value);
1424 case METADATA_EDITOR_ATTR_TRACK_NUM: return __ID3_setFrameByName(metadata, tag2, "TRCK", value);
1425 case METADATA_EDITOR_ATTR_CONDUCTOR: return __ID3_setFrameByName(metadata, tag2, "TPE3", value);
1426 case METADATA_EDITOR_ATTR_COMMENT: return __ID3_setTwixCommentFrame(metadata, NULL, tag2, value);
1427 case METADATA_EDITOR_ATTR_UNSYNCLYRICS: return __ID3_setLyricsFrame(metadata, tag2, value);
1429 return METADATA_EDITOR_ERROR_INVALID_PARAMETER;
1434 // *** This function is used to modify the metadata (frame in tag). But it does not apply changes to file *** //
1435 extern "C" int metadata_editor_set_metadata(metadata_editor_h metadata, metadata_editor_attr_e attribute, const char* value) {
1437 metadata_editor_s* _metadata = (metadata_editor_s*) metadata;
1438 metadata_editor_retvm_if(!_metadata, METADATA_EDITOR_ERROR_INVALID_PARAMETER, "Invalid metadata");
1440 switch (_metadata->filetype) { // Process the file according to the specified file type
1441 case METADATA_EDITOR_FORMAT_MP3:
1442 return __metadata_editor_set_mp3_metadata(_metadata, attribute, value);
1444 case METADATA_EDITOR_FORMAT_MP4:
1445 return __metadata_editor_set_mp4_metadata(_metadata, attribute, value);
1448 case METADATA_EDITOR_FORMAT_FLAC:
1449 return __metadata_editor_set_flac_metadata(_metadata, attribute, value);
1451 case METADATA_EDITOR_FORMAT_OGG_VORBIS:
1452 return __metadata_editor_set_ogg_vorbis_metadata(_metadata, attribute, value);
1454 case METADATA_EDITOR_FORMAT_OGG_FLAC:
1455 return __metadata_editor_set_ogg_flac_metadata(_metadata, attribute, value);
1457 case METADATA_EDITOR_FORMAT_WAV:
1458 return __metadata_editor_set_wav_metadata(_metadata, attribute, value);
1462 metadata_editor_error("Wrong file type");
1463 return METADATA_EDITOR_ERROR_INVALID_PARAMETER;
1467 // *** This function apply all changes done in the tag(s) and update them to file *** //
1468 extern "C" int metadata_editor_update_metadata(metadata_editor_h metadata) {
1469 int ret = METADATA_EDITOR_ERROR_NONE;
1470 metadata_editor_s* _metadata = (metadata_editor_s*) metadata;
1472 ret = __check_metadata_set_parameter(_metadata);
1473 metadata_editor_retvm_if(ret != METADATA_EDITOR_ERROR_NONE, ret, "fail to __check_metadata_set_parameter() [%d]", ret);
1475 switch (_metadata->filetype) { // Process the file according to the specified file type
1476 case METADATA_EDITOR_FORMAT_MP3: {
1477 // Bring the pointer to actual file type
1478 TagLib::MPEG::File* _file = (TagLib::MPEG::File*)_metadata->file;
1480 TagLib::ID3v1::Tag* tag1 = _file->ID3v1Tag();
1482 if (!tag1 || tag1->isEmpty()) { // If no ID3v1 tag - prevent its creation
1483 if (_file->save(TagLib::MPEG::File::ID3v2 | TagLib::MPEG::File::APE))
1484 return METADATA_EDITOR_ERROR_NONE;
1485 } else { // otherwise - save all tags in file
1486 if (_file->save(TagLib::MPEG::File::AllTags))
1487 return METADATA_EDITOR_ERROR_NONE;
1489 return METADATA_EDITOR_ERROR_OPERATION_FAILED;
1491 case METADATA_EDITOR_FORMAT_MP4: {
1492 TagLib::MP4::File* _file = (TagLib::MP4::File*)_metadata->file;
1494 return METADATA_EDITOR_ERROR_NONE;
1496 return METADATA_EDITOR_ERROR_OPERATION_FAILED;
1499 case METADATA_EDITOR_FORMAT_FLAC: {
1500 TagLib::FLAC::File* _file = (TagLib::FLAC::File*)_metadata->file;
1502 return METADATA_EDITOR_ERROR_NONE;
1504 return METADATA_EDITOR_ERROR_OPERATION_FAILED;
1506 case METADATA_EDITOR_FORMAT_OGG_VORBIS: {
1507 TagLib::Ogg::Vorbis::File* _file = (TagLib::Ogg::Vorbis::File*)_metadata->file;
1509 return METADATA_EDITOR_ERROR_NONE;
1511 return METADATA_EDITOR_ERROR_OPERATION_FAILED;
1513 case METADATA_EDITOR_FORMAT_OGG_FLAC: {
1514 TagLib::Ogg::FLAC::File* _file = (TagLib::Ogg::FLAC::File*)_metadata->file;
1516 return METADATA_EDITOR_ERROR_NONE;
1518 return METADATA_EDITOR_ERROR_OPERATION_FAILED;
1520 case METADATA_EDITOR_FORMAT_WAV: {
1521 TagLib::RIFF::WAV::File* _file = (TagLib::RIFF::WAV::File*)_metadata->file;
1523 return METADATA_EDITOR_ERROR_NONE;
1525 return METADATA_EDITOR_ERROR_OPERATION_FAILED;
1529 metadata_editor_error("Wrong file type");
1530 return METADATA_EDITOR_ERROR_INVALID_PARAMETER;
1534 // *** This function returns buffer with picture under the specified index and buffer's (picture's) size *** //
1535 extern "C" int metadata_editor_get_picture(metadata_editor_h metadata, int index, void **picture, int *size, char **mime_type) {
1536 const char *TYPE_JPEG = "image/jpeg";
1537 const char *TYPE_PNG = "image/png";
1539 int ret = METADATA_EDITOR_ERROR_NONE;
1541 metadata_editor_s* _metadata = (metadata_editor_s*) metadata;
1543 ret = __check_metadata_get_parameter(_metadata, mime_type);
1544 metadata_editor_retvm_if(ret != METADATA_EDITOR_ERROR_NONE, ret, "fail to __check_metadata_get_parameter() [%d]", ret);
1545 metadata_editor_retvm_if(!picture, METADATA_EDITOR_ERROR_INVALID_PARAMETER, "Invalid picture");
1546 metadata_editor_retvm_if(!size, METADATA_EDITOR_ERROR_INVALID_PARAMETER, "Invalid size");
1552 switch (_metadata->filetype) { // Process the file according to the specified file type
1553 case METADATA_EDITOR_FORMAT_MP3: {
1554 TagLib::MPEG::File* _file = (TagLib::MPEG::File*)_metadata->file; // Bring the pointer to actual file type
1555 TagLib::ID3v2::Tag* tag2 = _file->ID3v2Tag();
1556 metadata_editor_retvm_if(tag2 == NULL, METADATA_EDITOR_ERROR_OPERATION_FAILED, "Error. No ID3v2 tag in file.");
1558 TagLib::ID3v2::FrameList lst = tag2->frameListMap()["APIC"];
1559 // Check if there are pictures in the tag
1560 if (lst.isEmpty()) {
1561 metadata_editor_error("No pictures in file");
1562 return METADATA_EDITOR_ERROR_OPERATION_FAILED;
1563 } else { // pictures exist in file
1564 // Check if index is correct or not
1565 if ((index < 0) || (lst.size() <= (uint)index)) {
1566 metadata_editor_error("Index of picture is out of range");
1567 return METADATA_EDITOR_ERROR_INVALID_PARAMETER;
1568 } else { // everything is correct - begin extraction
1569 metadata_editor_info("There are %u pictures in file. Start of picture number %d extraction", lst.size(), index);
1571 // Among all frames we must choose that one with specified index. "i" will be counter
1572 for (TagLib::ID3v2::FrameList::Iterator it = lst.begin(); it != lst.end(); ++it, ++i) {
1573 if (i != index) continue;
1574 TagLib::ID3v2::AttachedPictureFrame* pictureFrame = static_cast<TagLib::ID3v2::AttachedPictureFrame*>(*it);
1575 uint pictureSize = pictureFrame->picture().size();
1576 metadata_editor_retvm_if(pictureSize == 0, METADATA_EDITOR_ERROR_OPERATION_FAILED, "Size of picture is 0");
1577 META_MALLOC(*picture, pictureSize);
1578 metadata_editor_retvm_if(*picture == NULL, METADATA_EDITOR_ERROR_OUT_OF_MEMORY, "OUT_OF_MEMORY");
1580 memcpy(*picture, pictureFrame->picture().data(), pictureSize);
1581 *size = pictureSize;
1582 TagLib::String mime = pictureFrame->mimeType();
1583 if (!strcmp(mime.toCString(), "image/jpeg"))
1584 *mime_type = strndup(TYPE_JPEG, strlen(TYPE_JPEG));
1585 else if (!strcmp(mime.toCString(), "image/png"))
1586 *mime_type = strndup(TYPE_PNG, strlen(TYPE_PNG));
1591 return METADATA_EDITOR_ERROR_NONE;
1595 case METADATA_EDITOR_FORMAT_MP4: {
1596 TagLib::MP4::File* _file = (TagLib::MP4::File*) _metadata->file;
1597 TagLib::MP4::Tag* tag = _file->tag();
1598 metadata_editor_retvm_if(tag == NULL, METADATA_EDITOR_ERROR_OPERATION_FAILED, "Tag does not exist");
1600 // Get map of items directly from tag and launch a search of specific item
1601 TagLib::MP4::ItemListMap& itemMap = tag->itemListMap();
1602 TagLib::MP4::ItemListMap::ConstIterator it = itemMap.find("covr");
1603 if (it != itemMap.end()) { // Item was found
1604 TagLib::MP4::CoverArtList lst = it->second.toCoverArtList();
1605 // Check if the index is in range of CoverArtList Item
1606 if ((index < 0) || ((uint)index >= lst.size())) { // it is not
1607 metadata_editor_error("Index of picture is out of range");
1608 return METADATA_EDITOR_ERROR_INVALID_PARAMETER;
1609 } else { // index is in range
1611 for (TagLib::MP4::CoverArtList::ConstIterator picIt = lst.begin(); picIt != lst.end(); ++picIt, ++i) {
1612 if (i != index) continue;
1613 int pictureSize = picIt->data().size();
1614 metadata_editor_retvm_if(pictureSize == 0, METADATA_EDITOR_ERROR_OPERATION_FAILED, "Size of picture is 0");
1615 META_MALLOC(*picture, pictureSize);
1616 metadata_editor_retvm_if(*picture == NULL, METADATA_EDITOR_ERROR_OUT_OF_MEMORY, "OUT_OF_MEMORY");
1618 memcpy(*picture, picIt->data().data(), pictureSize);
1619 *size = pictureSize;
1620 if (picIt->format() == TagLib::MP4::CoverArt::JPEG) *mime_type = strndup(TYPE_JPEG, strlen(TYPE_JPEG));
1621 else if (picIt->format() == TagLib::MP4::CoverArt::PNG) *mime_type = strndup(TYPE_PNG, strlen(TYPE_PNG));
1622 else *mime_type = NULL;
1625 return METADATA_EDITOR_ERROR_NONE;
1627 } else { // Item was not found - no pictures in file
1628 metadata_editor_error("No item <covr> in file. No pictures in file");
1629 return METADATA_EDITOR_ERROR_OPERATION_FAILED;
1633 case METADATA_EDITOR_FORMAT_FLAC: {
1634 TagLib::FLAC::File* _file = (TagLib::FLAC::File*) _metadata->file;
1635 TagLib::List<TagLib::FLAC::Picture*> lst = _file->pictureList();
1636 if (lst.isEmpty()) {
1637 metadata_editor_error("No pictures in FLAC file");
1638 return METADATA_EDITOR_ERROR_OPERATION_FAILED;
1640 // Check if the index is in range of CoverArtList Item
1641 if ((index < 0) || ((uint)index >= lst.size())) { // it is not
1642 metadata_editor_error("Index of picture is out of range");
1643 return METADATA_EDITOR_ERROR_INVALID_PARAMETER;
1644 } else { // index is in range
1645 // Consecutive check of all pictures until the desired one is found
1647 for (TagLib::List<TagLib::FLAC::Picture*>::ConstIterator picIt = lst.begin(); picIt != lst.end(); ++picIt, ++i) {
1648 if (i != index) continue;
1649 // picture can be received as ByteVector (picIt->data()).
1650 // ByteVector has data() - picture itself and size() - the size of picture in data() method
1651 int pictureSize = (*picIt)->data().size();
1652 metadata_editor_retvm_if(pictureSize == 0, METADATA_EDITOR_ERROR_OPERATION_FAILED, "Size of picture is 0");
1653 META_MALLOC(*picture, pictureSize);
1654 metadata_editor_retvm_if(*picture == NULL, METADATA_EDITOR_ERROR_OUT_OF_MEMORY, "OUT_OF_MEMORY");
1656 memcpy(*picture, (*picIt)->data().data(), pictureSize);
1657 *size = pictureSize;
1658 TagLib::String mime = (*picIt)->mimeType();
1659 if (!strcmp(mime.toCString(), "image/jpeg"))
1660 *mime_type = strndup(TYPE_JPEG, strlen(TYPE_JPEG));
1661 else if (!strcmp(mime.toCString(), "image/png"))
1662 *mime_type = strndup(TYPE_PNG, strlen(TYPE_PNG));
1667 return METADATA_EDITOR_ERROR_NONE;
1671 case METADATA_EDITOR_FORMAT_WAV: {
1672 TagLib::RIFF::WAV::File* _file = (TagLib::RIFF::WAV::File*)_metadata->file; // Bring the pointer to actual file type
1673 TagLib::ID3v2::Tag* tag2 = _file->tag();
1675 metadata_editor_error("No ID3v2 tag in file");
1676 return METADATA_EDITOR_ERROR_OPERATION_FAILED;
1678 TagLib::ID3v2::FrameList lst = tag2->frameListMap()["APIC"];
1679 // Check if there are pictures in the tag
1680 if (lst.isEmpty()) {
1681 metadata_editor_error("No pictures in file");
1682 return METADATA_EDITOR_ERROR_OPERATION_FAILED;
1683 } else { // pictures exist in file
1684 // Check if index is correct or not
1685 if ((index < 0) || (lst.size() <= (uint)index)) {
1686 metadata_editor_error("Index of picture is out of range");
1687 return METADATA_EDITOR_ERROR_INVALID_PARAMETER;
1688 } else { // everything is correct - begin extraction
1689 metadata_editor_info("There are %u pictures in file. Start of picture number %d extraction", lst.size(), index);
1691 // Among all frames we must choose that one with specified index. "i" will be counter
1692 for (TagLib::ID3v2::FrameList::Iterator it = lst.begin(); it != lst.end(); ++it, ++i) {
1693 if (i != index) continue;
1694 TagLib::ID3v2::AttachedPictureFrame* pictureFrame = static_cast<TagLib::ID3v2::AttachedPictureFrame*>(*it);
1695 uint pictureSize = pictureFrame->picture().size();
1696 metadata_editor_retvm_if(pictureSize == 0, METADATA_EDITOR_ERROR_OPERATION_FAILED, "Size of picture is 0");
1698 META_MALLOC(*picture, pictureSize);
1699 metadata_editor_retvm_if(*picture == NULL, METADATA_EDITOR_ERROR_OUT_OF_MEMORY, "OUT_OF_MEMORY");
1701 memcpy(*picture, pictureFrame->picture().data(), pictureSize);
1702 *size = pictureSize;
1703 TagLib::String mime = pictureFrame->mimeType();
1704 if (!strcmp(mime.toCString(), "image/jpeg"))
1705 *mime_type = strndup(TYPE_JPEG, strlen(TYPE_JPEG));
1706 else if (!strcmp(mime.toCString(), "image/png"))
1707 *mime_type = strndup(TYPE_PNG, strlen(TYPE_PNG));
1712 return METADATA_EDITOR_ERROR_NONE;
1718 metadata_editor_error("Wrong file type");
1719 return METADATA_EDITOR_ERROR_INVALID_PARAMETER;
1723 // *** This function appends a cover art picture to the file *** //
1724 extern "C" int metadata_editor_append_picture(metadata_editor_h metadata, const char *path) {
1725 int ret = METADATA_EDITOR_ERROR_NONE;
1726 void *picture = NULL;
1730 metadata_editor_s* _metadata = (metadata_editor_s*) metadata;
1732 ret = __check_metadata_set_parameter(_metadata);
1733 metadata_editor_retvm_if(ret != METADATA_EDITOR_ERROR_NONE, ret, "fail to __check_metadata_set_parameter() [%d]", ret);
1734 metadata_editor_retvm_if(!path, METADATA_EDITOR_ERROR_INVALID_PARAMETER, "Invalid path");
1736 ret = __metadata_editor_get_picture_info(path, &picture, &size, &type);
1737 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");
1739 switch (_metadata->filetype) { // Process the file according to the specified file type
1740 case METADATA_EDITOR_FORMAT_MP3: {
1741 // Bring the pointer to actual file type and make tags pointers
1742 TagLib::MPEG::File* _file = (TagLib::MPEG::File*)_metadata->file;
1743 TagLib::ID3v2::Tag* tag2 = _file->ID3v2Tag(true);
1744 // Check if the valid tag pointer exists
1746 metadata_editor_error("Error. ID3v2 tag was not created. Can not proceed metadata updating");
1747 ret = METADATA_EDITOR_ERROR_OPERATION_FAILED;
1750 TagLib::ID3v2::AttachedPictureFrame* pictureFrame = new TagLib::ID3v2::AttachedPictureFrame();
1751 if (pictureFrame == NULL) {
1752 metadata_editor_error("OUT_OF_MEMORY");
1753 ret = METADATA_EDITOR_ERROR_OUT_OF_MEMORY;
1756 metadata_editor_info("New APIC frame will be added to the ID3v2 tag");
1757 pictureFrame->setPicture(TagLib::ByteVector((char*)picture, size));
1758 pictureFrame->setType(TagLib::ID3v2::AttachedPictureFrame::FrontCover);
1759 pictureFrame->setMimeType(type);
1761 tag2->addFrame(pictureFrame);
1763 ret = METADATA_EDITOR_ERROR_NONE;
1766 case METADATA_EDITOR_FORMAT_MP4: {
1767 TagLib::MP4::File* _file = (TagLib::MP4::File*) _metadata->file;
1768 TagLib::MP4::Tag* tag = _file->tag();
1770 metadata_editor_error("Tag was not created");
1771 ret = METADATA_EDITOR_ERROR_OPERATION_FAILED;
1775 // Get map of items directly from tag and launch a search of specific item
1776 TagLib::MP4::ItemListMap& itemMap = tag->itemListMap();
1777 TagLib::MP4::ItemListMap::ConstIterator it = itemMap.find("covr");
1778 if (it != itemMap.end()) { // Item was found
1779 metadata_editor_info("The item <covr> exists. Adding picture");
1780 TagLib::MP4::CoverArtList lst = it->second.toCoverArtList();
1781 TagLib::MP4::CoverArt::Format format;
1782 if (strncmp(type, "image/jpeg", strlen("image/jpeg")) == 0)
1783 format = TagLib::MP4::CoverArt::JPEG;
1784 else if (strncmp(type, "image/png", strlen("image/jpeg")) == 0)
1785 format = TagLib::MP4::CoverArt::PNG;
1787 format = (TagLib::MP4::CoverArt::Format)0xFFFF;
1788 TagLib::MP4::CoverArt cover(format, TagLib::ByteVector((char*)picture, size));
1790 itemMap.insert("covr", TagLib::MP4::Item(lst));
1792 ret = METADATA_EDITOR_ERROR_NONE;
1794 } else { // Item was not found
1795 metadata_editor_info("The item <covr> does not exist. Adding picture");
1796 TagLib::MP4::CoverArt::Format format;
1797 if (strncmp(type, "image/jpeg", strlen("image/jpeg")) == 0)
1798 format = TagLib::MP4::CoverArt::JPEG;
1799 else if (strncmp(type, "image/png", strlen("image/jpeg")) == 0)
1800 format = TagLib::MP4::CoverArt::PNG;
1802 format = (TagLib::MP4::CoverArt::Format)0xFFFF;
1803 TagLib::MP4::CoverArt cover(format, TagLib::ByteVector((char*)picture, size));
1804 TagLib::MP4::CoverArtList lst;
1806 itemMap.insert("covr", TagLib::MP4::Item(lst));
1808 ret = METADATA_EDITOR_ERROR_NONE;
1813 case METADATA_EDITOR_FORMAT_FLAC: {
1814 TagLib::FLAC::File* _file = (TagLib::FLAC::File*) _metadata->file;
1815 TagLib::FLAC::Picture* frontCover = new TagLib::FLAC::Picture;
1816 if (frontCover == NULL) {
1817 metadata_editor_error("OUT_OF_MEMORY");
1818 ret = METADATA_EDITOR_ERROR_OUT_OF_MEMORY;
1821 frontCover->setData(TagLib::ByteVector((char*)picture, size));
1822 frontCover->setType(TagLib::FLAC::Picture::FrontCover);
1823 frontCover->setMimeType(type);
1825 metadata_editor_info("Picture will be added to FLAC file");
1826 _file->addPicture(frontCover);
1827 ret = METADATA_EDITOR_ERROR_NONE;
1830 case METADATA_EDITOR_FORMAT_WAV: {
1831 // Bring the pointer to actual file type and make tags pointers
1832 TagLib::RIFF::WAV::File* _file = (TagLib::RIFF::WAV::File*)_metadata->file;
1833 TagLib::ID3v2::Tag* tag2 = _file->tag();
1834 // Check if the valid tag pointer exists
1836 metadata_editor_error("Error. ID3v2 tag was not created. Can not proceed metadata updating");
1837 ret = METADATA_EDITOR_ERROR_OPERATION_FAILED;
1840 TagLib::ID3v2::AttachedPictureFrame* pictureFrame = new TagLib::ID3v2::AttachedPictureFrame();
1841 if (pictureFrame == NULL) {
1842 metadata_editor_error("OUT_OF_MEMORY");
1843 ret = METADATA_EDITOR_ERROR_OUT_OF_MEMORY;
1846 metadata_editor_info("New APIC frame will be added to the ID3v2 tag");
1847 pictureFrame->setPicture(TagLib::ByteVector((char*)picture, size));
1848 pictureFrame->setType(TagLib::ID3v2::AttachedPictureFrame::FrontCover);
1849 pictureFrame->setMimeType(type);
1850 tag2->addFrame(pictureFrame);
1851 ret = METADATA_EDITOR_ERROR_NONE;
1856 metadata_editor_error("Wrong file type");
1857 ret = METADATA_EDITOR_ERROR_NOT_SUPPORTED;
1862 META_SAFE_FREE(picture);
1863 META_SAFE_FREE(type);
1868 // *** This function is used to delete picture with specified index *** //
1869 extern "C" int metadata_editor_remove_picture(metadata_editor_h metadata, int index) {
1870 int ret = METADATA_EDITOR_ERROR_NONE;
1871 metadata_editor_s* _metadata = (metadata_editor_s*) metadata;
1873 ret = __check_metadata_set_parameter(_metadata);
1874 metadata_editor_retvm_if(ret != METADATA_EDITOR_ERROR_NONE, ret, "fail to __check_metadata_set_parameter() [%d]", ret);
1876 switch (_metadata->filetype) { // Process the file according to the specified file type
1877 case METADATA_EDITOR_FORMAT_MP3: {
1878 // Bring the pointer to actual file type and make tags pointers
1879 TagLib::MPEG::File* _file = (TagLib::MPEG::File*)_metadata->file;
1880 TagLib::ID3v2::Tag* tag2 = _file->ID3v2Tag(true);
1881 // Check if the valid tag pointer exists
1882 metadata_editor_retvm_if(tag2 == NULL, METADATA_EDITOR_ERROR_OPERATION_FAILED, "Error. ID3v2 tag was not created. Can not proceed metadata updating");
1883 TagLib::ID3v2::FrameList lst = tag2->frameListMap()["APIC"];
1884 // Check if there are pictures in the tag
1885 metadata_editor_retvm_if(lst.isEmpty(), METADATA_EDITOR_ERROR_OPERATION_FAILED, "No pictures in file");
1887 // Check if index is correct or not
1888 metadata_editor_retvm_if((index < 0) || (lst.size() <= (uint)index), METADATA_EDITOR_ERROR_INVALID_PARAMETER, "Index of picture is out of range");
1889 metadata_editor_info("Removing of picture number %d", index);
1891 // Among all frames we must choose that one with specified index. "i" will be counter
1892 for (TagLib::ID3v2::FrameList::Iterator it = lst.begin(); it != lst.end(); ++it, ++i) {
1893 if (i != index) continue;
1894 tag2->removeFrame(*it);
1897 return METADATA_EDITOR_ERROR_NONE;
1899 case METADATA_EDITOR_FORMAT_MP4: {
1900 TagLib::MP4::File* _file = (TagLib::MP4::File*) _metadata->file;
1901 TagLib::MP4::Tag* tag = _file->tag();
1902 metadata_editor_retvm_if(tag == NULL, METADATA_EDITOR_ERROR_OPERATION_FAILED, "Error. tag not exist.");
1904 // Get map of items directly from tag and launch a search of specific item
1905 TagLib::MP4::ItemListMap& itemMap = tag->itemListMap();
1906 TagLib::MP4::ItemListMap::ConstIterator it = itemMap.find("covr");
1907 if (it != itemMap.end()) { // Item was found
1908 TagLib::MP4::CoverArtList lst = it->second.toCoverArtList();
1909 // Check if the index is in range of CoverArtList Item
1910 if ((index < 0) || ((uint)index >= lst.size())) { // it is not
1911 metadata_editor_error("Index of picture is out of range");
1912 return METADATA_EDITOR_ERROR_INVALID_PARAMETER;
1913 } else { // index is in range
1914 metadata_editor_info("The picture number %d will be deleted", index);
1916 for (TagLib::MP4::CoverArtList::Iterator picIt = lst.begin(); picIt != lst.end(); ++picIt, ++i) {
1917 if (i != index) continue;
1921 itemMap.insert("covr", TagLib::MP4::Item(lst));
1922 return METADATA_EDITOR_ERROR_NONE;
1924 } else { // Item was not found
1925 metadata_editor_error("The item <covr> does not exist. Nothing to delete");
1926 return METADATA_EDITOR_ERROR_OPERATION_FAILED;
1930 case METADATA_EDITOR_FORMAT_FLAC: {
1931 TagLib::FLAC::File* _file = (TagLib::FLAC::File*) _metadata->file;
1932 TagLib::List<TagLib::FLAC::Picture*> lst = _file->pictureList();
1933 if (lst.isEmpty()) {
1934 metadata_editor_error("No pictures in file. Nothing to delete");
1935 return METADATA_EDITOR_ERROR_OPERATION_FAILED;
1937 // Check if the index is in range of CoverArtList Item
1938 if ((index < 0) || ((uint)index >= lst.size())) { // it is not
1939 metadata_editor_error("Index of picture is out of range");
1940 return METADATA_EDITOR_ERROR_INVALID_PARAMETER;
1941 } else { // index is in range
1942 metadata_editor_info("The picture number %d will be deleted", index);
1944 for (TagLib::List<TagLib::FLAC::Picture*>::Iterator picIt = lst.begin(); picIt != lst.end(); ++picIt, ++i) {
1945 if (i != index) continue;
1946 _file->removePicture(*picIt, true);
1949 return METADATA_EDITOR_ERROR_NONE;
1952 case METADATA_EDITOR_FORMAT_WAV: {
1953 // Bring the pointer to actual file type and make tags pointers
1954 TagLib::RIFF::WAV::File* _file = (TagLib::RIFF::WAV::File*)_metadata->file;
1955 TagLib::ID3v2::Tag* tag2 = _file->tag();
1956 // Check if the valid tag pointer exists
1958 metadata_editor_error("Error. ID3v2 tag does not exist. Can not remove picture");
1959 return METADATA_EDITOR_ERROR_OPERATION_FAILED;
1961 TagLib::ID3v2::FrameList lst = tag2->frameListMap()["APIC"];
1962 // Check if there are pictures in the tag
1963 if (lst.isEmpty()) {
1964 metadata_editor_error("No pictures in file");
1965 return METADATA_EDITOR_ERROR_OPERATION_FAILED;
1966 } else { // pictures exist in file
1967 // Check if index is correct or not
1968 if ((index < 0) || (lst.size() <= (uint)index)) {
1969 metadata_editor_error("Index of picture is out of range");
1970 return METADATA_EDITOR_ERROR_INVALID_PARAMETER;
1971 } else { // everything is correct - begin extraction
1972 metadata_editor_info("Removing of picture number %d", index);
1974 // Among all frames we must choose that one with specified index. "i" will be counter
1975 for (TagLib::ID3v2::FrameList::Iterator it = lst.begin(); it != lst.end(); ++it, ++i) {
1976 if (i != index) continue;
1977 tag2->removeFrame(*it);
1980 return METADATA_EDITOR_ERROR_NONE;
1986 metadata_editor_error("Wrong file type");
1987 return METADATA_EDITOR_ERROR_INVALID_PARAMETER;
1991 // *** This function is used to free memory that was allocated with metadata_editor_create(...) and metadata_editor_set_path(...) functions *** //
1992 extern "C" int metadata_editor_destroy(metadata_editor_h metadata) {
1993 metadata_editor_s *_metadata = (metadata_editor_s*)metadata;
1994 metadata_editor_retvm_if(!_metadata, METADATA_EDITOR_ERROR_INVALID_PARAMETER, "Invalid metadata");
1996 switch (_metadata->filetype) {
1997 case METADATA_EDITOR_FORMAT_MP3: {
1998 // Bring the pointer to actual file type
1999 TagLib::MPEG::File* _file = (TagLib::MPEG::File*)_metadata->file;
2000 metadata_editor_info("file free [%p]", _metadata->file);
2004 case METADATA_EDITOR_FORMAT_MP4: {
2005 TagLib::MP4::File* _file = (TagLib::MP4::File*)_metadata->file;
2006 metadata_editor_info("file free [%p]", _metadata->file);
2011 case METADATA_EDITOR_FORMAT_FLAC: {
2012 TagLib::FLAC::File* _file = (TagLib::FLAC::File*)_metadata->file;
2013 metadata_editor_info("file free [%p]", _metadata->file);
2017 case METADATA_EDITOR_FORMAT_OGG_VORBIS: {
2018 TagLib::Ogg::Vorbis::File* _file = (TagLib::Ogg::Vorbis::File*)_metadata->file;
2019 metadata_editor_info("file free [%p]", _metadata->file);
2023 case METADATA_EDITOR_FORMAT_OGG_FLAC: {
2024 TagLib::Ogg::FLAC::File* _file = (TagLib::Ogg::FLAC::File*)_metadata->file;
2025 metadata_editor_info("file free [%p]", _metadata->file);
2029 case METADATA_EDITOR_FORMAT_WAV: {
2030 TagLib::RIFF::WAV::File* _file = (TagLib::RIFF::WAV::File*)_metadata->file;
2031 metadata_editor_info("file free [%p]", _metadata->file);
2037 metadata_editor_error("Wrong file type");
2038 return METADATA_EDITOR_ERROR_INVALID_PARAMETER;
2041 metadata_editor_info("<metadata_editor_s> with address %p will be freed", metadata);
2044 return METADATA_EDITOR_ERROR_NONE;