4 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: Haejeong Kim <backto.kim@samsung.com>
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
29 #include "mm_file_debug.h"
30 #include "mm_file_utils.h"
32 #define ENABLE_ITUNES_META /*All itunes metadata extracted by ffmpeg. see mov_read_udta_string() but Some cover art not support. */
34 typedef struct _mmfilemp4basicboxheader {
37 long long start_offset; /*huge file*/
38 } MMFILE_MP4_BASIC_BOX_HEADER;
40 typedef struct _mmfilemp4ftpybox {
41 unsigned int major_brand;
42 unsigned short major_version;
43 unsigned short minor_version;
44 unsigned int *compatiable_brands;
48 eMMFILE_3GP_TAG_TITLE = 0x01,
49 eMMFILE_3GP_TAG_CAPTION = 0x02,
50 eMMFILE_3GP_TAG_COPYRIGHT = 0x03,
51 eMMFILE_3GP_TAG_PERFORMER = 0x04,
52 eMMFILE_3GP_TAG_AUTHOR = 0x05,
53 eMMFILE_3GP_TAG_GENRE = 0x06,
54 } eMMFILE_3GP_TEXT_TAG;
56 typedef struct _mmfile3gptagtextbox {
57 unsigned char version;
58 unsigned char flag[3];
59 unsigned char language[2];
61 } MMFILE_3GP_TEXT_TAGBOX;
63 typedef struct _mmfile3gptagyearbox {
64 unsigned char version;
65 unsigned char flag[3];
67 } MMFILE_3GP_YEAR_TAGBOX;
69 typedef struct _mmfile3gptagalbumbox {
70 unsigned char version;
71 unsigned char flag[3];
72 unsigned char language[2];
73 unsigned char *albumtile;
74 unsigned char trackNumber;
75 } MMFILE_3GP_ALBUM_TAGBOX;
77 typedef struct _mmfile3gpratingbox {
78 unsigned char version;
79 unsigned char flag[3];
80 unsigned int ratingEntity;
81 unsigned int ratingCriteria;
82 unsigned char language[2];
83 unsigned char *ratingInfo;
84 } MMFILE_3GP_RATING_TAGBOX;
86 typedef struct _mmfile3gpclsfbox {
87 unsigned char version;
88 unsigned char flag[3];
89 unsigned int classificationEntity;
90 unsigned int classificationTable;
91 unsigned char language[2];
92 unsigned char *classificationInfo;
93 } MMFILE_3GP_CLASSIFICATION_TAGBOX;
95 typedef struct _mmfile3gphdlrbox {
97 unsigned int pre_defined;
98 unsigned int handler_type;
99 unsigned int reserved[3];
100 unsigned char *boxname;
101 } MMFILE_3GP_HANDLER_BOX;
103 typedef struct _mmfileidv2box {
104 unsigned char version;
105 unsigned char flag[3];
106 unsigned char language[2];
107 unsigned char *id3v2Data;
108 } MMFILE_3GP_ID3V2_BOX;
110 typedef struct _mmfilelocibox {
111 unsigned char version;
112 unsigned char flag[3];
113 unsigned char language[2];
119 unsigned char *astronomical_body;
120 unsigned char *additional_notes;
121 } MMFILE_3GP_LOCATION_TAGBOX;
123 typedef struct _mmfilesmtabox {
126 unsigned char saut[4];
128 } MMFILE_M4A_SMTA_TAGBOX;
130 #define MMFILE_MP4_BASIC_BOX_HEADER_LEN 8
131 #define MMFILE_MP4_MOVIE_HEADER_BOX_LEN 96
132 #define MMFILE_MP4_HDLR_BOX_LEN 24
133 #define MMFILE_MP4_STSZ_BOX_LEN 20
134 #define MMFILE_MP4_MP4VBOX_LEN 80
135 #define MMFILE_MP4_MP4ABOX_LEN 28
136 #define MMFILE_3GP_TEXT_TAGBOX_LEN 6
137 #define MMFILE_3GP_YEAR_TAGBOX_LEN 6
138 #define MMFILE_3GP_ALBUM_TAGBOX_LEN 6
139 #define MMFILE_3GP_RATING_TAGBOX_LEN 14
140 #define MMFILE_3GP_CLASS_TAGBOX_LEN 14
141 #define MMFILE_3GP_HANDLER_BOX_LEN 24
142 #define MMFILE_3GP_ID3V2_BOX_LEN 6
143 #define MMFILE_SYNC_LYRIC_INFO_MIN_LEN 5
146 #define FOURCC(a, b, c, d) ((a) + ((b) << 8) + ((c) << 16) + ((d) << 24))
148 /*#define MIN(a, b) (((a) < (b)) ? (a):(b))*/
150 #define GENRE_COUNT 149
152 static const char *MpegAudio_Genre[GENRE_COUNT] = {"Blues", "Classic Rock", "Country", "Dance", "Disco", "Funk", "Grunge", "Hip-Hop", "Jazz", "Metal",
153 "New Age", "Oldies", "Other", "Pop", "R&B", "Rap", "Reggae", "Rock", "Techno", "Industrial",
154 "Alternative", "Ska", "Death Metal", "Pranks", "Soundtrack", "Euro-Techno", "Ambient", "Trip-Hop", "Vocal", "Jazz+Funk",
155 "Fusion", "Trance", "Classical", "Instrumental", "Acid", "House", "Game", "Sound Clip", "Gospel", "Noise",
156 "AlternRock", "Bass", "Soul", "Punk", "Space", "Meditative", "Instrumental Pop", "Instrumental Rock", "Ethnic", "Gothic",
157 "Darkwave", "Techno-Industrial", "Electronic", "Pop-Folk", "Eurodance", "Dream", "Southern Rock", "Comedy", "Cult", "Gangsta",
158 "Top 40", "Christian Rap", "Pop/Funk", "Jungle", "Native American", "Cabaret", "New Wave", "Psychadelic", "Rave", "Showtunes",
159 "Trailer", "Lo-Fi", "Tribal", "Acid Punk", "Acid Jazz", "Polka", "Retro", "Musical", "Rock & Roll", "Hard Rock",
160 "Folk", "Folk-Rock", "National Folk", "Swing", "Fast Fusion", "Bebob", "Latin", "Revival", "Celtic", "Bluegrass",
161 "Avantgarde", "Gothic Rock", "Progressive Rock", "Psychedelic Rock", "Symphonic Rock", "Slow Rock", "Big Band", "Chorus", "Easy Listening", "Acoustic",
162 "Humour", "Speech", "Chanson", "Opera", "Chamber Music", "Sonata", "Symphony", "Booty Bass", "Primus", "Porn Groove",
163 "Satire", "Slow Jam", "Club", "Tango", "Samba", "Folklore", "Ballad", "Power Ballad", "Rhythmic Soul", "Freestyle",
164 "Duet", "Punk Rock", "Drum Solo", "A capella", "Euro-House", "Dance Hall", "Goa", "Drum & Bass", "Club-House", "Hardcore",
165 "Terror", "Indie", "BritPop", "Negerpunk", "Polsk Punk", "Beat", "Christian", "Heavy Metal", "Black Metal", "Crossover",
166 "Contemporary", "Christian Rock", "Merengue", "Salsa", "Thrash Metal", "Anime", "JPop", "Synthpop", "Unknown"
169 static unsigned char gTagJPEGHeader[] = {0xff, 0xd8, 0xff };
170 static unsigned char gTagPNGHeader[] = {0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a };
172 static int GetStringFromTextTagBox(MMFileFormatContext *formatContext, MMFileIOHandle *fp, MMFILE_MP4_BASIC_BOX_HEADER *basic_header, eMMFILE_3GP_TEXT_TAG eTag)
174 int ret = MMFILE_UTIL_FAIL; /*fail*/
175 MMFILE_3GP_TEXT_TAGBOX texttag = {0, };
178 char *temp_text = NULL;
180 if (!formatContext || !fp || !basic_header) {
181 debug_error("invalid param\n");
182 return MMFILE_UTIL_FAIL;
185 textBytes = basic_header->size - MMFILE_MP4_BASIC_BOX_HEADER_LEN - MMFILE_3GP_TEXT_TAGBOX_LEN;
187 readed = mmfile_read(fp, (unsigned char *)&texttag, MMFILE_3GP_TEXT_TAGBOX_LEN);
188 if (readed != MMFILE_3GP_TEXT_TAGBOX_LEN) {
189 debug_error("read text tag header fail\n");
190 ret = MMFILE_UTIL_FAIL;
194 if (textBytes <= 1) { /* there exist only 00(null) */
195 debug_error("Text is NULL\n");
199 texttag.text = mmfile_malloc(textBytes);
201 debug_error("malloc fail for text box\n");
202 ret = MMFILE_UTIL_FAIL;
206 readed = mmfile_read(fp, (unsigned char *)texttag.text, textBytes);
207 if (readed != textBytes) {
208 debug_error("read text fail\n");
209 ret = MMFILE_UTIL_FAIL;
214 if ((texttag.text[0] == 0xFE) && (texttag.text[1] == 0xFF)) {
215 /* this char is UTF-16 */
216 unsigned int bytes_written = 0;
217 temp_text = mmfile_string_convert((const char *)&texttag.text[2], readed - 2, "UTF-8", "UTF-16", NULL, (unsigned int *)&bytes_written);
219 temp_text = mmfile_strdup((const char *)texttag.text);
223 case eMMFILE_3GP_TAG_TITLE: {
224 if (!formatContext->title) {
225 formatContext->title = temp_text;
229 case eMMFILE_3GP_TAG_CAPTION: {
230 if (!formatContext->description) {
231 formatContext->description = temp_text;
235 case eMMFILE_3GP_TAG_COPYRIGHT: {
236 if (!formatContext->copyright) {
237 formatContext->copyright = temp_text;
241 case eMMFILE_3GP_TAG_PERFORMER: {
242 if (!formatContext->artist) {
243 formatContext->artist = temp_text;
247 case eMMFILE_3GP_TAG_AUTHOR: {
248 if (!formatContext->author) {
249 formatContext->author = temp_text;
253 case eMMFILE_3GP_TAG_GENRE: {
254 if (!formatContext->genre) {
255 formatContext->genre = temp_text;
260 debug_warning("Not supported Text Tag type[%d]\n", eTag);
265 mmfile_free(texttag.text);
267 mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
269 return MMFILE_UTIL_SUCCESS;
272 mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
274 mmfile_free(texttag.text);
279 static int GetYearFromYearTagBox(MMFileFormatContext *formatContext, MMFileIOHandle *fp, MMFILE_MP4_BASIC_BOX_HEADER *basic_header)
281 #define MAX_YEAR_BUFFER 10
283 MMFILE_3GP_YEAR_TAGBOX yearbox = {0, };
284 char temp_year[MAX_YEAR_BUFFER] = {0, };
286 if (!formatContext || !fp || !basic_header) {
287 debug_error("invalid param\n");
288 return MMFILE_UTIL_FAIL;
291 readed = mmfile_read(fp, (unsigned char *)&yearbox, MMFILE_3GP_YEAR_TAGBOX_LEN);
292 if (readed != MMFILE_3GP_YEAR_TAGBOX_LEN) {
293 debug_error("read yeartag header fail\n");
297 if (!formatContext->year) {
298 yearbox.year = mmfile_io_be_int16(yearbox.year);
299 snprintf(temp_year, MAX_YEAR_BUFFER, "%d", yearbox.year);
300 temp_year[MAX_YEAR_BUFFER - 1] = '\0';
301 formatContext->year = mmfile_strdup((const char *)temp_year);
304 mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
305 return MMFILE_UTIL_SUCCESS;
308 mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
310 return MMFILE_UTIL_FAIL;
313 static int GetAlbumFromAlbumTagBox(MMFileFormatContext *formatContext, MMFileIOHandle *fp, MMFILE_MP4_BASIC_BOX_HEADER *basic_header)
315 int albumTitleLen = 0;
316 char *temp_text = NULL;
319 MMFILE_3GP_ALBUM_TAGBOX albumbox = {0, };
321 if (!formatContext || !fp || !basic_header) {
322 debug_error("invalid param\n");
323 return MMFILE_UTIL_FAIL;
326 readed = mmfile_read(fp, (unsigned char *)&albumbox, MMFILE_3GP_ALBUM_TAGBOX_LEN);
327 if (readed != MMFILE_3GP_ALBUM_TAGBOX_LEN) {
328 debug_error("read albumtag header fail\n");
332 albumTitleLen = basic_header->size - MMFILE_MP4_BASIC_BOX_HEADER_LEN - MMFILE_3GP_ALBUM_TAGBOX_LEN - 1; /* 1: track number */
333 if (albumTitleLen > 1) { /* there exist only 00(null) */
334 #ifdef __MMFILE_TEST_MODE__
335 debug_msg("albumTitleLen=%d\n", albumTitleLen);
338 albumbox.albumtile = mmfile_malloc(albumTitleLen + 1); /* 1: for null char */
339 if (!albumbox.albumtile) {
340 debug_error("malloc fail for album title text\n");
344 readed = mmfile_read(fp, (unsigned char *)albumbox.albumtile, albumTitleLen);
345 if (readed != albumTitleLen) {
346 debug_error("read album title fail\n");
350 if (albumbox.albumtile[albumTitleLen - 1] == '\0') { /* there exist track number */
354 readed = mmfile_read(fp, (unsigned char *)&(albumbox.albumtile[albumTitleLen]), 1);
356 debug_error("read album title fail\n");
359 albumbox.albumtile[albumTitleLen] = '\0';
363 if ((albumbox.albumtile[0] == 0xFE) && (albumbox.albumtile[1] == 0xFF)) {
364 /* this char is UTF-16 */
365 unsigned int bytes_written = 0;
366 temp_text = mmfile_string_convert((const char *)&albumbox.albumtile[2], readed - 2, "UTF-8", "UTF-16", NULL, (unsigned int *)&bytes_written);
368 temp_text = mmfile_strdup((const char *)albumbox.albumtile);
371 if (!formatContext->album) {
372 formatContext->album = temp_text;
375 #ifdef __MMFILE_TEST_MODE__
376 debug_msg("formatContext->album=%s, strlen=%d\n", formatContext->album, strlen(formatContext->album));
381 readed = mmfile_read(fp, (unsigned char *)&albumbox.trackNumber, 1);
383 debug_error("read track number fail\n");
387 if (formatContext->tagTrackNum == 0) {
388 char tracknum[10] = {0, };
389 snprintf(tracknum, 10, "%d", albumbox.trackNumber);
391 formatContext->tagTrackNum = mmfile_strdup((const char *)tracknum);
395 mmfile_free(albumbox.albumtile);
396 mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
398 return MMFILE_UTIL_SUCCESS;
401 mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
402 mmfile_free(albumbox.albumtile);
404 return MMFILE_UTIL_FAIL;
407 static int GetRatingFromRatingTagBox(MMFileFormatContext *formatContext, MMFileIOHandle *fp, MMFILE_MP4_BASIC_BOX_HEADER *basic_header)
410 int ratinginfoLen = 0;
411 char *temp_text = NULL;
413 MMFILE_3GP_RATING_TAGBOX ratingTag = {0, };
415 if (!formatContext || !fp || !basic_header) {
416 debug_error("invalid param\n");
417 return MMFILE_UTIL_FAIL;
420 readed = mmfile_read(fp, (unsigned char *)&ratingTag, MMFILE_3GP_RATING_TAGBOX_LEN);
421 if (readed != MMFILE_3GP_RATING_TAGBOX_LEN) {
422 debug_error("read rating tag header fail\n");
426 ratinginfoLen = basic_header->size - MMFILE_MP4_BASIC_BOX_HEADER_LEN - MMFILE_3GP_RATING_TAGBOX_LEN;
428 if (ratinginfoLen == 1) {
429 debug_error("Rating Text is NULL\n");
433 ratingTag.ratingInfo = mmfile_malloc(ratinginfoLen);
434 if (!ratingTag.ratingInfo) {
435 debug_error("rating info error\n");
439 readed = mmfile_read(fp, (unsigned char *)ratingTag.ratingInfo, ratinginfoLen);
440 if (readed != ratinginfoLen) {
441 debug_error("read rating info string fail\n");
446 if ((ratingTag.ratingInfo[0] == 0xFE) && (ratingTag.ratingInfo[1] == 0xFF)) {
447 /* this char is UTF-16 */
448 unsigned int bytes_written = 0;
449 temp_text = mmfile_string_convert((const char *)&ratingTag.ratingInfo[2], readed - 2, "UTF-8", "UTF-16", NULL, (unsigned int *)&bytes_written);
451 temp_text = mmfile_strdup((const char *)ratingTag.ratingInfo);
454 if (!formatContext->rating) {
455 formatContext->rating = temp_text;
457 mmfile_free(temp_text);
460 mmfile_free(ratingTag.ratingInfo);
461 mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
463 return MMFILE_UTIL_SUCCESS;
466 mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
467 mmfile_free(ratingTag.ratingInfo);
469 return MMFILE_UTIL_FAIL;
473 static int GetClassficationFromClsfTagBox(MMFileFormatContext *formatContext, MMFileIOHandle *fp, MMFILE_MP4_BASIC_BOX_HEADER *basic_header)
475 int classinfoLen = 0;
477 char *temp_text = NULL;
478 MMFILE_3GP_CLASSIFICATION_TAGBOX classTag = {0, };
480 if (!formatContext || !fp || !basic_header) {
481 debug_error("invalid param\n");
482 return MMFILE_UTIL_FAIL;
485 readed = mmfile_read(fp, (unsigned char *)&classTag, MMFILE_3GP_CLASS_TAGBOX_LEN);
486 if (readed != MMFILE_3GP_CLASS_TAGBOX_LEN) {
487 debug_error("read classification tag header fail\n");
492 classinfoLen = basic_header->size - MMFILE_MP4_BASIC_BOX_HEADER_LEN - MMFILE_3GP_CLASS_TAGBOX_LEN;
493 if (classinfoLen == 1) {
494 debug_error("Classification Text is NULL\n");
498 classTag.classificationInfo = mmfile_malloc(classinfoLen);
499 if (!classTag.classificationInfo) {
500 debug_error("class info error\n");
504 readed = mmfile_read(fp, (unsigned char *)classTag.classificationInfo, classinfoLen);
505 if (readed != classinfoLen) {
506 debug_error("read class info string fail\n");
511 if ((classTag.classificationInfo[0] == 0xFE) && (classTag.classificationInfo[1] == 0xFF)) {
512 /* this char is UTF-16 */
513 unsigned int bytes_written = 0;
514 temp_text = mmfile_string_convert((const char *)&classTag.classificationInfo[2], readed - 2, "UTF-8", "UTF-16", NULL, (unsigned int *)&bytes_written);
516 temp_text = mmfile_strdup((const char *)classTag.classificationInfo);
519 if (!formatContext->classification) {
520 formatContext->classification = temp_text;
522 mmfile_free(temp_text);
525 mmfile_free(classTag.classificationInfo);
526 mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
528 return MMFILE_UTIL_SUCCESS;
531 mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
532 mmfile_free(classTag.classificationInfo);
534 return MMFILE_UTIL_FAIL;
538 * The Location Information box
539 * --------------------+-------------------+-----------------------------------+------
540 * Field Type Details Value
541 * --------------------+-------------------+-----------------------------------+------
542 * BoxHeader.Size Unsigned int(32)
543 * BoxHeader.Type Unsigned int(32) 'loci'
544 * BoxHeader.Version Unsigned int(8) 0
545 * BoxHeader.Flags Bit(24) 0
547 * Language Unsigned int(5)[3] Packed ISO-639-2/T language code
548 * Name String Text of place name
549 * Role Unsigned int(8) Non-negative value indicating role
551 * Longitude Unsigned int(32) Fixed-point value of the longitude
552 * Latitude Unsigned int(32) Fixed-point value of the latitude
553 * Altitude Unsigned int(32) Fixed-point value of the Altitude
554 * Astronomical_body String Text of astronomical body
555 * Additional_notes String Text of additional location-related
557 * --------------------+-------------------+-----------------------------------+------
559 static int _get_char_position(unsigned char *src, char ch, int max)
562 for (i = 0; i < max; i++) {
563 if (*(src + i) == ch)
570 static int GetLocationFromLociTagBox(MMFileFormatContext *formatContext, MMFileIOHandle *fp, MMFILE_MP4_BASIC_BOX_HEADER *basic_header)
573 MMFILE_3GP_LOCATION_TAGBOX lociTag = {0, };
576 unsigned char *buffer = NULL;
577 unsigned char *p = NULL;
579 unsigned int bytes_written = 0;
580 unsigned int name_sz = 0;
581 unsigned int astro_sz = 0;
583 int ilong, ilati, ialti;
584 float flong, flati, falti;
587 if (!formatContext || !fp || !basic_header) {
588 debug_error("invalid param\n");
589 return MMFILE_UTIL_FAIL;
592 readed = mmfile_read(fp, (unsigned char *)&lociTag, 6); /*6 = version + flag + pad + language */
594 debug_error("read location tag header fail\n");
598 /*buffer len = name + role + ... + additional notes length */
599 bufferLen = basic_header->size - MMFILE_MP4_BASIC_BOX_HEADER_LEN - 6;
601 debug_error("too small buffer\n");
605 buffer = mmfile_malloc(bufferLen);
607 debug_error("buffer malloc error\n");
611 readed = mmfile_read(fp, (unsigned char *)buffer, bufferLen);
612 if (readed != bufferLen) {
613 debug_error("read location tag fail\n");
619 pos = _get_char_position(p, '\0', readed - (1 + 4 + 4 + 4 + 2));
621 if (p[0] == 0xFE && p[1] == 0xFF) {
622 lociTag.name = (unsigned char *)mmfile_string_convert((const char *)(p + 2), pos - 2, "UTF-8", "UTF-16", NULL, (unsigned int *)&bytes_written);
624 lociTag.name = (unsigned char *)mmfile_strdup((const char *)p);
636 #ifdef __MMFILE_TEST_MODE__
637 debug_msg("long: 0x%02X 0x%02X 0x%02X 0x%02X \n", *(p + 0), *(p + 1), *(p + 2), *(p + 3));
638 debug_msg("lati: 0x%02X 0x%02X 0x%02X 0x%02X \n", *(p + 4), *(p + 5), *(p + 6), *(p + 7));
639 debug_msg("alti: 0x%02X 0x%02X 0x%02X 0x%02X \n", *(p + 8), *(p + 9), *(p + 10), *(p + 11));
642 ilong = mmfile_io_be_uint32(*(unsigned int *)p);
643 ilati = mmfile_io_be_uint32(*(unsigned int *)(p + 4));
644 ialti = mmfile_io_be_uint32(*(unsigned int *)(p + 8));
646 flong = (float)ilong / (1 << 16);
647 flati = (float)ilati / (1 << 16);
648 falti = (float)ialti / (1 << 16);
651 lociTag.longitude = flong;
653 lociTag.latitude = flati;
655 lociTag.altitude = falti;
659 /*astronomical body*/
660 pos = _get_char_position(p, '\0', readed - (name_sz + 1 + 4 + 4 + 4 + 1));
662 if (p[0] == 0xFE && p[1] == 0xFF) {
663 lociTag.astronomical_body = (unsigned char *)mmfile_string_convert((const char *)(p + 2), pos - 2, "UTF-8", "UTF-16", NULL, (unsigned int *)&bytes_written);
665 lociTag.astronomical_body = (unsigned char *)mmfile_strdup((const char *)p);
674 pos = _get_char_position(p, '\0', readed - (name_sz + 1 + 4 + 4 + 4 + astro_sz));
676 if (p[0] == 0xFE && p[1] == 0xFF) {
677 lociTag.additional_notes = (unsigned char *)mmfile_string_convert((const char *)(p + 2), pos - 2, "UTF-8", "UTF-16", NULL, (unsigned int *)&bytes_written);
679 lociTag.additional_notes = (unsigned char *)mmfile_strdup((const char *)p);
685 #ifdef __MMFILE_TEST_MODE__
686 debug_msg("** Location Information **\n");
687 debug_msg("Name : %s\n", lociTag.name);
688 debug_msg("Role : %d (0: shooting, 1: real, 2: fictional, other: reserved)\n", lociTag.role);
689 debug_msg("Longitude : %16.16f\n", lociTag.longitude);
690 debug_msg("Latitude : %16.16f\n", lociTag.latitude);
691 debug_msg("Altitude : %16.16f\n", lociTag.altitude);
692 debug_msg("Astronomical body: %s\n", lociTag.astronomical_body);
693 debug_msg("Additional notes : %s\n", lociTag.additional_notes);
696 formatContext->longitude = lociTag.longitude;
697 formatContext->latitude = lociTag.latitude;
698 formatContext->altitude = lociTag.altitude;
701 mmfile_free(lociTag.name);
702 mmfile_free(lociTag.astronomical_body);
703 mmfile_free(lociTag.additional_notes);
705 mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
706 return MMFILE_UTIL_SUCCESS;
709 mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
711 mmfile_free(lociTag.name);
712 mmfile_free(lociTag.astronomical_body);
713 mmfile_free(lociTag.additional_notes);
715 return MMFILE_UTIL_FAIL;
718 static int GetSAUTInfoFromSMTATagBox(MMFileFormatContext *formatContext, MMFileIOHandle *fp, MMFILE_MP4_BASIC_BOX_HEADER *basic_header)
720 MMFILE_M4A_SMTA_TAGBOX smtaTag = {0, };
723 if (!formatContext || !fp || !basic_header) {
724 debug_error("invalid param\n");
725 return MMFILE_UTIL_FAIL;
728 readed = mmfile_read(fp, (unsigned char *)&smtaTag, sizeof(MMFILE_M4A_SMTA_TAGBOX));
729 if (readed != sizeof(MMFILE_M4A_SMTA_TAGBOX)) {
730 debug_error("read smta tag header fail\n");
734 smtaTag.length = mmfile_io_be_uint32(smtaTag.length);
735 smtaTag.value = mmfile_io_be_uint32(smtaTag.value);
736 #ifdef __MMFILE_TEST_MODE__
737 debug_msg("Len : 0x%x", smtaTag.length);
738 debug_msg("Saut : 0x%x 0x%x 0x%x 0x%x", smtaTag.saut[0], smtaTag.saut[1], smtaTag.saut[2], smtaTag.saut[3]);
739 debug_msg("Value : 0x%x", smtaTag.value);
742 if (smtaTag.saut[0] == 's'
743 && smtaTag.saut[1] == 'a'
744 && smtaTag.saut[2] == 'u'
745 && smtaTag.saut[3] == 't') {
746 if (smtaTag.value == 0x01) {
747 #ifdef __MMFILE_TEST_MODE__
748 debug_msg("This has saut tag and valid value");
750 formatContext->smta = 1;
752 debug_error("This has saut tag and but invalid value");
756 debug_error("This hasn't saut tag and valid value");
760 return MMFILE_UTIL_SUCCESS;
763 mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
765 return MMFILE_UTIL_FAIL;
768 static int GetValueFromCDISTagBox(MMFileFormatContext *formatContext, MMFileIOHandle *fp, MMFILE_MP4_BASIC_BOX_HEADER *basic_header)
770 unsigned int value = 0;
773 if (!formatContext || !fp || !basic_header) {
774 debug_error("invalid param\n");
775 return MMFILE_UTIL_FAIL;
778 readed = mmfile_read(fp, (unsigned char *)&value, sizeof(unsigned int));
779 if (readed != sizeof(unsigned int)) {
780 debug_error("read cdis tag header fail\n");
784 value = mmfile_io_be_uint32(value);
786 #ifdef __MMFILE_TEST_MODE__
787 debug_msg("Value : 0x%x", value);
791 #ifdef __MMFILE_TEST_MODE__
792 debug_msg("This has cdis tag and valid value");
794 formatContext->cdis = 1;
796 debug_error("This has cdis tag and but invalid value");
800 return MMFILE_UTIL_SUCCESS;
803 mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
805 return MMFILE_UTIL_FAIL;
808 static int GetTagFromMetaBox(MMFileFormatContext *formatContext, MMFileIOHandle *fp, MMFILE_MP4_BASIC_BOX_HEADER *basic_header)
811 MMFILE_MP4_BASIC_BOX_HEADER hdlrBoxHeader = {0, };
812 MMFILE_MP4_BASIC_BOX_HEADER id3v2BoxHeader = {0, };
813 MMFILE_3GP_ID3V2_BOX id3v2Box = {0, };
814 AvFileContentInfo tagInfo = {0, };
815 unsigned char tagVersion = 0;
816 bool versionCheck = false;
818 unsigned int meta_version = 0;
819 MMFILE_3GP_HANDLER_BOX hdlrBox = {0, };
820 unsigned int encSize = 0;
822 #ifdef ENABLE_ITUNES_META /* We don't support itunes meta now. so this is not defined yet */
827 readed = mmfile_read(fp, (unsigned char *)&meta_version, 4);
829 debug_error("read meta box version\n");
834 readed = mmfile_read(fp, (unsigned char *)&hdlrBoxHeader, MMFILE_MP4_BASIC_BOX_HEADER_LEN);
835 if (readed != MMFILE_MP4_BASIC_BOX_HEADER_LEN) {
836 debug_error("read hdlr box header\n");
840 if (hdlrBoxHeader.type != FOURCC('h', 'd', 'l', 'r')) {
841 debug_warning("meta type is not hdlr\n");
845 hdlrBoxHeader.size = mmfile_io_be_uint32(hdlrBoxHeader.size);
846 hdlrBoxHeader.type = mmfile_io_le_uint32(hdlrBoxHeader.type);
848 readed = mmfile_read(fp, (unsigned char *)&hdlrBox, MMFILE_3GP_HANDLER_BOX_LEN);
849 if (readed != MMFILE_3GP_HANDLER_BOX_LEN) {
850 debug_error("read hdlr box\n");
854 hdlrBox.handler_type = mmfile_io_le_uint32(hdlrBox.handler_type);
857 * check tag type (ID3v2 or iTunes)
859 if (hdlrBox.handler_type == FOURCC('I', 'D', '3', '2')) {
860 #ifdef __MMFILE_TEST_MODE__
861 debug_msg("ID3v2 tag detected.\n");
865 #ifdef ENABLE_ITUNES_META
868 } else if (hdlrBox.handler_type == FOURCC('m', 'd', 'i', 'r') &&
869 mmfile_io_le_uint32(hdlrBox.reserved[0]) == FOURCC('a', 'p', 'p', 'l')) {
871 #ifdef __MMFILE_TEST_MODE__
872 debug_msg("Apple iTunes tag detected by mdir.\n");
875 #ifdef ENABLE_ITUNES_META
879 debug_warning("unknown meta type. 4CC:[%c%c%c%c]\n", ((char *)&hdlrBox.handler_type)[0],
880 ((char *)&hdlrBox.handler_type)[1],
881 ((char *)&hdlrBox.handler_type)[2],
882 ((char *)&hdlrBox.handler_type)[3]);
886 #ifdef ENABLE_ITUNES_META
887 if (!id3_meta && !iTunes_meta) {
889 APPLE meta data for iTunes reader = 'mdir.' so if handler type is 'mdir', this content may has itunes meta.
890 most of contents has 'mdir' + 'appl'. but some contents just has 'mdir'
891 but 'ilst' is meta for iTunes. so find 'ilst' is more correct to check if this contents has iTunes meta or not.*/
893 const char *ilst_box = "ilst";
894 int buf_size = strlen(ilst_box);
896 unsigned char read_buf[buf_size + 1];
897 memset(read_buf, 0x00, buf_size + 1);
900 mmfile_seek(fp, hdlrBoxHeader.size - MMFILE_MP4_BASIC_BOX_HEADER_LEN - MMFILE_3GP_HANDLER_BOX_LEN + 4, SEEK_CUR); /*+4 is hdlr size field */
902 readed = mmfile_read(fp, read_buf, buf_size); /* to find 'ilst' */
903 if (readed != buf_size) {
904 debug_error("read fail [%d]\n", readed);
908 if (read_buf[0] == 'i' && read_buf[1] == 'l' && read_buf[2] == 's' && read_buf[3] == 't') {
909 #ifdef __MMFILE_TEST_MODE__
910 debug_msg("Apple iTunes tag detected by ilst.\n");
918 #ifdef ENABLE_ITUNES_META
921 * iTunes (Cover[?ovr] & Track[trkn] only extract!) + Genre/Artist : Added 2010.10.27,28
929 #define _ITUNES_READ_BUF_SZ 20
930 #define _ITUNES_TRACK_NUM_SZ 4
931 #define _ITUNES_GENRE_NUM_SZ 4
932 #define _ITUNES_COVER_TYPE_JPEG 13
933 #define _ITUNES_COVER_TYPE_PNG 14
935 unsigned char read_buf[_ITUNES_READ_BUF_SZ];
937 int cover_sz = 0, cover_type = 0, cover_found = 0;
938 /* int track_found = 0; */ /* , track_num = 0; */
939 /* int genre_found = 0; */ /* , genre_index = 0; */
940 /* int artist_found = 0; */ /* , artist_sz = 0; */
941 int limit = basic_header->size - hdlrBoxHeader.size;
942 long long cover_offset = 0; /*, track_offset =0, genre_offset = 0, artist_offset = 0; */
944 /* for (i = 0, cover_found = 0, track_found = 0, genre_found = 0, artist_found = 0; i < limit && (cover_found == 0 || track_found == 0 || genre_found == 0 || artist_found == 0) ; i++) { */
945 for (i = 0; (i < limit) && (cover_found == 0) ; i++) {
946 readed = mmfile_read(fp, read_buf, _ITUNES_READ_BUF_SZ);
947 if (readed != _ITUNES_READ_BUF_SZ)
950 /*ffmpeg extract artist, tracknum, genre and cover image. see mov_read_udta_string().
951 but ffmpeg does not support strange cover image.
952 only support covr type 0xd(JPEG), 0xe(PNG), 0x1b(BMP). but we support other type*/
955 * Artist : Added 2010.10.28
957 if (artist_found == 0 &&
958 read_buf[0] == 0xa9 && read_buf[1] == 'A' && read_buf[2] == 'R' && read_buf[3] == 'T' &&
959 read_buf[8] == 'd' && read_buf[9] == 'a' && read_buf[10] == 't' && read_buf[11] == 'a') {
962 artist_offset = mmfile_tell(fp);
963 artist_sz = mmfile_io_be_uint32(*(int *)(read_buf + 4)) - 16; /* atom len(4)+data(4)+atom verion(1)+flag(3)+null(4) = 16 */
965 #ifdef __MMFILE_TEST_MODE__
966 debug_msg("----------------------------------- artist found, offset=[%lld], size=[%d]\n", artist_offset, artist_sz);
973 if (track_found == 0 &&
974 read_buf[0] == 't' && read_buf[1] == 'r' && read_buf[2] == 'k' && read_buf[3] == 'n' &&
975 read_buf[8] == 'd' && read_buf[9] == 'a' && read_buf[10] == 't' && read_buf[11] == 'a') {
978 track_offset = mmfile_tell(fp);
980 #ifdef __MMFILE_TEST_MODE__
981 debug_msg("----------------------------------- Track found, offset=[%lld]\n", track_offset);
986 * Genre : Added 2010.10.27
988 /*ffmpeg extract genre but only (0xa9,'g','e','n'). see mov_read_udta_string()*/
989 if (genre_found == 0 &&
990 read_buf[0] == 'g' && read_buf[1] == 'n' && read_buf[2] == 'r' && read_buf[3] == 'e' &&
991 read_buf[8] == 'd' && read_buf[9] == 'a' && read_buf[10] == 't' && read_buf[11] == 'a') {
994 genre_offset = mmfile_tell(fp);
996 #ifdef __MMFILE_TEST_MODE__
997 debug_msg("----------------------------------- genre found, offset=[%lld]\n", genre_offset);
1006 if (cover_found == 0 &&
1007 read_buf[0] == 'c' && read_buf[1] == 'o' && read_buf[2] == 'v' && read_buf[3] == 'r' &&
1008 read_buf[8] == 'd' && read_buf[9] == 'a' && read_buf[10] == 't' && read_buf[11] == 'a') {
1011 cover_sz = mmfile_io_be_uint32(*(int *)(read_buf + 4)) - 12;
1012 cover_type = mmfile_io_be_uint32(*(int *)(read_buf + 12));
1014 cover_offset = mmfile_tell(fp);
1016 #ifdef __MMFILE_TEST_MODE__
1017 debug_msg("----------------------------------- cover_found found, offset=[%lld]\n", cover_offset);
1021 mmfile_seek(fp, -(_ITUNES_READ_BUF_SZ - 1), SEEK_CUR); /*FIXME: poor search*/
1024 /*ffmpeg extract artist, tracknum, excep cover image. see mov_read_udta_string()*/
1027 if (artist_sz > 0) {
1028 mmfile_seek(fp, artist_offset, SEEK_SET);
1030 if (formatContext->artist) {
1031 #ifdef __MMFILE_TEST_MODE__
1032 debug_msg("----------------------------------- previous artist was [%s] \n", formatContext->artist);
1034 free(formatContext->artist);
1036 #ifdef __MMFILE_TEST_MODE__
1037 debug_msg("----------------------------------- new artist will be allocated with size (len+1) [%d] \n", artist_sz + 1);
1039 formatContext->artist = mmfile_malloc(artist_sz + 1);
1041 if (formatContext->artist) {
1042 readed = mmfile_read(fp, (unsigned char *)formatContext->artist, artist_sz);
1043 formatContext->artist[artist_sz] = '\0';
1045 #ifdef __MMFILE_TEST_MODE__
1046 debug_msg("----------------------------------- new artist is [%s] \n", formatContext->artist);
1049 if (readed != artist_sz) {
1050 debug_error("failed to read. ret = %d, in = %d\n", readed, artist_sz);
1051 mmfile_free(formatContext->artist);
1058 mmfile_seek(fp, track_offset, SEEK_SET);
1059 readed = mmfile_read(fp, read_buf, _ITUNES_TRACK_NUM_SZ);
1060 if (readed != _ITUNES_TRACK_NUM_SZ) {
1061 debug_error("failed to read. ret = %d, in = %d\n", readed, _ITUNES_TRACK_NUM_SZ);
1063 track_num = mmfile_io_be_uint32(*(int *)read_buf);
1064 if (!formatContext->tagTrackNum) {
1065 memset(read_buf, 0x00, _ITUNES_READ_BUF_SZ);
1066 snprintf((char *)read_buf, sizeof(read_buf), "%d", track_num);
1067 formatContext->tagTrackNum = mmfile_strdup((const char *)read_buf);
1073 mmfile_seek(fp, genre_offset, SEEK_SET);
1074 readed = mmfile_read(fp, read_buf, _ITUNES_GENRE_NUM_SZ);
1075 if (readed != _ITUNES_GENRE_NUM_SZ) {
1076 debug_error("failed to read. ret = %d, in = %d\n", readed, _ITUNES_GENRE_NUM_SZ);
1078 genre_index = mmfile_io_be_uint16(*(int *)read_buf);
1079 #ifdef __MMFILE_TEST_MODE__
1080 debug_msg("genre index=[%d] \n", genre_index);
1082 if (genre_index > 0 && genre_index < GENRE_COUNT) {
1083 if (!formatContext->genre) {
1084 memset(read_buf, 0x00, _ITUNES_READ_BUF_SZ);
1085 snprintf((char *)read_buf, sizeof(read_buf), "%s", MpegAudio_Genre[genre_index - 1]);
1086 #ifdef __MMFILE_TEST_MODE__
1087 debug_msg("genre string=[%s] \n", read_buf);
1089 formatContext->genre = mmfile_strdup((const char *)read_buf);
1097 1) below spec is in "iTunes Package Asset Specification 4.3" published by apple.
1098 Music Cover Art Image Profile
1099 - TIFF with ".tif" extension (32-bit uncompressed), JPEG with ".jpg" extension (quality unconstrained), or PNG with ".png" extension
1100 - RGB (screen standard)
1101 - Minimum size of 600 x 600 pixels
1102 - Images must be at least 72 dpi
1104 2)I found below info from google.
1105 cover image flag : JPEG (13, 0xd), PNG (14, 0xe)
1107 3)So, FIXME when cover image format is tif!
1111 mmfile_seek(fp, cover_offset, SEEK_SET);
1113 formatContext->artwork = mmfile_malloc(cover_sz);
1114 formatContext->artworkSize = cover_sz;
1115 if (cover_type == _ITUNES_COVER_TYPE_JPEG) {
1116 formatContext->artworkMime = mmfile_strdup("image/jpeg");
1117 } else if (cover_type == _ITUNES_COVER_TYPE_PNG) {
1118 formatContext->artworkMime = mmfile_strdup("image/png");
1119 /*} else if(cover_type == _ITUNES_COVER_TYPE_TIF) {
1120 formatContext->artworkMime = mmfile_strdup("image/tif");*/
1122 debug_warning("Not proper cover image type, but set to jpeg. cover_type[%d]", cover_type);
1123 formatContext->artworkMime = mmfile_strdup("image/jpeg");
1126 if (formatContext->artwork) {
1127 readed = mmfile_read(fp, formatContext->artwork, cover_sz);
1128 if (readed != cover_sz) {
1129 debug_error("failed to read. ret = %d, in = %d\n", readed, cover_sz);
1130 mmfile_free(formatContext->artwork);
1131 formatContext->artworkSize = 0;
1132 mmfile_free(formatContext->artworkMime);
1138 /*reset seek position*/
1139 mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
1141 return MMFILE_UTIL_SUCCESS;
1149 /* skip hdlr box name */
1150 mmfile_seek(fp, hdlrBoxHeader.size - MMFILE_MP4_BASIC_BOX_HEADER_LEN - MMFILE_3GP_HANDLER_BOX_LEN, SEEK_CUR);
1153 readed = mmfile_read(fp, (unsigned char *)&id3v2BoxHeader, MMFILE_MP4_BASIC_BOX_HEADER_LEN);
1154 if (readed != MMFILE_MP4_BASIC_BOX_HEADER_LEN) {
1155 debug_error("read id3v2 box header\n");
1159 id3v2BoxHeader.size = mmfile_io_be_uint32(id3v2BoxHeader.size);
1160 id3v2BoxHeader.type = mmfile_io_le_uint32(id3v2BoxHeader.type);
1162 if (id3v2BoxHeader.type != FOURCC('I', 'D', '3', '2')) {
1163 debug_warning("meta type is not id3v2\n");
1167 readed = mmfile_read(fp, (unsigned char *)&id3v2Box, MMFILE_3GP_ID3V2_BOX_LEN);
1168 if (readed != MMFILE_3GP_ID3V2_BOX_LEN) {
1169 debug_error("read id3v2 box\n");
1173 id3v2Len = id3v2BoxHeader.size - MMFILE_MP4_BASIC_BOX_HEADER_LEN - MMFILE_3GP_ID3V2_BOX_LEN;
1175 id3v2Box.id3v2Data = mmfile_malloc(id3v2Len);
1176 if (!id3v2Box.id3v2Data) {
1177 debug_error("malloc id3tag data error\n");
1181 readed = mmfile_read(fp, (unsigned char *)id3v2Box.id3v2Data, id3v2Len);
1182 if (readed != id3v2Len) {
1183 debug_error("read id3tag data error\n");
1188 if (!IS_ID3V2_TAG(id3v2Box.id3v2Data)) {
1189 debug_error("it is not id3tag\n");
1193 if (id3v2Box.id3v2Data[3] == 0xFF || id3v2Box.id3v2Data[4] == 0xFF ||
1194 id3v2Box.id3v2Data[6] >= 0x80 || id3v2Box.id3v2Data[7] >= 0x80 ||
1195 id3v2Box.id3v2Data[8] >= 0x80 || id3v2Box.id3v2Data[9] >= 0x80) {
1196 debug_error("it is not valid id3tag\n");
1200 tagVersion = id3v2Box.id3v2Data[3];
1201 if (tagVersion > 4) {
1202 debug_error("tag vesion is too high\n");
1206 encSize = mmfile_io_le_uint32((unsigned int)&id3v2Box.id3v2Data[6]);
1207 tagInfo.tagV2Info.tagLen = MP3_TAGv2_HEADER_LEN;
1208 tagInfo.tagV2Info.tagLen += (((encSize & 0x0000007F) >> 0) | ((encSize & 0x00007F00) >> 1) | ((encSize & 0x007F0000) >> 2) | ((encSize & 0x7F000000) >> 3));
1209 tagInfo.tagV2Info.tagVersion = tagVersion;
1210 tagInfo.fileLen = id3v2Len;
1212 /* set id3v2 data to formatContext */
1213 switch (tagVersion) {
1215 versionCheck = mm_file_id3tag_parse_v222(&tagInfo, id3v2Box.id3v2Data);
1219 versionCheck = mm_file_id3tag_parse_v223(&tagInfo, id3v2Box.id3v2Data);
1223 versionCheck = mm_file_id3tag_parse_v224(&tagInfo, id3v2Box.id3v2Data);
1228 debug_error("tag vesion is not support\n");
1229 versionCheck = false;
1234 if (versionCheck == false) {
1235 debug_error("tag parsing is fail\n");
1239 if (!formatContext->title) formatContext->title = mmfile_strdup((const char *)tagInfo.pTitle);
1240 if (!formatContext->artist) formatContext->artist = mmfile_strdup((const char *)tagInfo.pArtist);
1241 if (!formatContext->author) formatContext->author = mmfile_strdup((const char *)tagInfo.pAuthor);
1242 if (!formatContext->copyright) formatContext->copyright = mmfile_strdup((const char *)tagInfo.pCopyright);
1243 if (!formatContext->comment) formatContext->comment = mmfile_strdup((const char *)tagInfo.pComment);
1244 if (!formatContext->album) formatContext->album = mmfile_strdup((const char *)tagInfo.pAlbum);
1245 if (!formatContext->album_artist) formatContext->album_artist = mmfile_strdup((const char *)tagInfo.pAlbum_Artist);
1246 if (!formatContext->year) formatContext->year = mmfile_strdup((const char *)tagInfo.pYear);
1247 if (!formatContext->genre) formatContext->genre = mmfile_strdup((const char *)tagInfo.pGenre);
1248 if (!formatContext->tagTrackNum) formatContext->tagTrackNum = mmfile_strdup((const char *)tagInfo.pTrackNum);
1249 if (!formatContext->composer) formatContext->composer = mmfile_strdup((const char *)tagInfo.pComposer);
1250 if (!formatContext->classification) formatContext->classification = mmfile_strdup((const char *)tagInfo.pContentGroup);
1251 if (!formatContext->conductor) formatContext->conductor = mmfile_strdup((const char *)tagInfo.pConductor);
1253 formatContext->artwork = mmfile_malloc(tagInfo.imageInfo.imageLen);
1254 if ((tagInfo.imageInfo.imageLen > 0) && formatContext->artwork) {
1255 formatContext->artworkSize = tagInfo.imageInfo.imageLen;
1256 memcpy(formatContext->artwork, tagInfo.imageInfo.pImageBuf, tagInfo.imageInfo.imageLen);
1259 mm_file_free_AvFileContentInfo(&tagInfo);
1260 mmfile_free(id3v2Box.id3v2Data);
1262 /*reset seek position*/
1263 mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
1265 return MMFILE_UTIL_SUCCESS;
1271 mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
1272 mmfile_free(id3v2Box.id3v2Data);
1273 mm_file_free_AvFileContentInfo(&tagInfo);
1275 return MMFILE_UTIL_FAIL;
1279 #define BIG_CONTENT_BOX_SIZE_LEN 8
1280 EXPORT_API int MMFileUtilGetMetaDataFromMP4(MMFileFormatContext *formatContext)
1282 MMFileIOHandle *fp = NULL;
1285 unsigned long long chunk_size = 0;
1287 ret = mmfile_open(&fp, formatContext->uriFileName, MMFILE_RDONLY);
1288 if (ret == MMFILE_UTIL_FAIL) {
1289 debug_error("error: mmfile_open\n");
1293 MMFILE_MP4_BASIC_BOX_HEADER basic_header = {0, };
1294 basic_header.start_offset = mmfile_tell(fp);
1296 while ((ret != MMFILE_UTIL_FAIL) && ((readed = mmfile_read(fp, (unsigned char *)&basic_header, MMFILE_MP4_BASIC_BOX_HEADER_LEN)) > 0)) {
1297 basic_header.size = mmfile_io_be_uint32(basic_header.size);
1298 basic_header.type = mmfile_io_le_uint32(basic_header.type);
1300 if (basic_header.size == 0) {
1301 debug_warning("header is invalid.\n");
1302 basic_header.size = readed;
1303 basic_header.type = 0;
1304 chunk_size = basic_header.size;
1305 } else if (basic_header.size == 1) {
1307 unsigned char temp[BIG_CONTENT_BOX_SIZE_LEN] = {0, };
1308 unsigned long long size = 0;
1310 mmfile_read(fp, (unsigned char *)&temp, BIG_CONTENT_BOX_SIZE_LEN);
1312 for(i = 0; i < BIG_CONTENT_BOX_SIZE_LEN; i++)
1313 size |= (unsigned long long)temp[i] << (BIG_CONTENT_BOX_SIZE_LEN - 1 - i) * BIG_CONTENT_BOX_SIZE_LEN;
1316 chunk_size = basic_header.size;
1319 #ifdef __MMFILE_TEST_MODE__
1320 debug_msg("START_OFFSET:[%lld] SIZE:[%d Byte] 4CC:[%c%c%c%c]\n",
1321 basic_header.start_offset, basic_header.size,
1322 ((char *)&basic_header.type)[0], ((char *)&basic_header.type)[1],
1323 ((char *)&basic_header.type)[2], ((char *)&basic_header.type)[3]);
1326 switch (basic_header.type) {
1327 case FOURCC('m', 'o', 'o', 'v'): {
1328 #ifdef __MMFILE_TEST_MODE__
1329 debug_msg("MPEG4: [moov] SIZE: [%lld]Byte\n", chunk_size);
1333 case FOURCC('u', 'd', 't', 'a'): {
1334 #ifdef __MMFILE_TEST_MODE__
1335 debug_msg("MPEG4: [udat] SIZE: [%lld]Byte\n", chunk_size);
1339 /*/////////////////////////////////////////////////////////////// */
1340 /* Extracting Tag Data // */
1341 /*/////////////////////////////////////////////////////////////// */
1342 case FOURCC('t', 'i', 't', 'l'): {
1343 #ifdef __MMFILE_TEST_MODE__
1344 debug_msg("MPEG4: [titl] SIZE: [%lld]Byte\n", chunk_size);
1346 GetStringFromTextTagBox(formatContext, fp, &basic_header, eMMFILE_3GP_TAG_TITLE);
1349 case FOURCC('d', 's', 'c', 'p'): {
1350 #ifdef __MMFILE_TEST_MODE__
1351 debug_msg("MPEG4: [dscp] SIZE: [%lld]Byte\n", chunk_size);
1353 GetStringFromTextTagBox(formatContext, fp, &basic_header, eMMFILE_3GP_TAG_CAPTION);
1356 case FOURCC('c', 'p', 'r', 't'): {
1357 #ifdef __MMFILE_TEST_MODE__
1358 debug_msg("MPEG4: [cprt] SIZE: [%lld]Byte\n", chunk_size);
1360 GetStringFromTextTagBox(formatContext, fp, &basic_header, eMMFILE_3GP_TAG_COPYRIGHT);
1363 case FOURCC('p', 'e', 'r', 'f'): {
1364 #ifdef __MMFILE_TEST_MODE__
1365 debug_msg("MPEG4: [perf] SIZE: [%lld]Byte\n", chunk_size);
1367 GetStringFromTextTagBox(formatContext, fp, &basic_header, eMMFILE_3GP_TAG_PERFORMER);
1370 case FOURCC('a', 'u', 't', 'h'): {
1371 #ifdef __MMFILE_TEST_MODE__
1372 debug_msg("MPEG4: [auth] SIZE: [%lld]Byte\n", chunk_size);
1374 GetStringFromTextTagBox(formatContext, fp, &basic_header, eMMFILE_3GP_TAG_AUTHOR);
1377 case FOURCC('g', 'n', 'r', 'e'): {
1378 #ifdef __MMFILE_TEST_MODE__
1379 debug_msg("MPEG4: [gnre] SIZE: [%lld]Byte\n", chunk_size);
1381 GetStringFromTextTagBox(formatContext, fp, &basic_header, eMMFILE_3GP_TAG_GENRE);
1384 case FOURCC('a', 'l', 'b', 'm'): {
1385 #ifdef __MMFILE_TEST_MODE__
1386 debug_msg("MPEG4: [albm] SIZE: [%lld]Byte\n", chunk_size);
1388 GetAlbumFromAlbumTagBox(formatContext, fp, &basic_header);
1391 case FOURCC('y', 'r', 'r', 'c'): {
1392 #ifdef __MMFILE_TEST_MODE__
1393 debug_msg("MPEG4: [yrrc] SIZE: [%lld]Byte\n", chunk_size);
1395 GetYearFromYearTagBox(formatContext, fp, &basic_header);
1398 case FOURCC('r', 't', 'n', 'g'): {
1399 #ifdef __MMFILE_TEST_MODE__
1400 debug_msg("MPEG4: [rtng] SIZE: [%lld]Byte\n", chunk_size);
1402 GetRatingFromRatingTagBox(formatContext, fp, &basic_header); /* not use */
1405 case FOURCC('c', 'l', 's', 'f'): {
1406 #ifdef __MMFILE_TEST_MODE__
1407 debug_msg("MPEG4: [clsf] SIZE: [%lld]Byte\n", chunk_size);
1409 GetClassficationFromClsfTagBox(formatContext, fp, &basic_header);
1412 case FOURCC('k', 'y', 'w', 'd'): {
1413 #ifdef __MMFILE_TEST_MODE__
1414 debug_msg("MPEG4: [kywd] SIZE: [%lld]Byte\n", chunk_size);
1416 ret = mmfile_seek(fp, basic_header.start_offset + chunk_size, SEEK_SET);
1419 case FOURCC('l', 'o', 'c', 'i'): {
1420 #ifdef __MMFILE_TEST_MODE__
1421 debug_msg("MPEG4: [loci] SIZE: [%lld]Byte\n", chunk_size);
1423 GetLocationFromLociTagBox(formatContext, fp, &basic_header);
1426 /* Check smta in user data field to be compatible with android */
1427 case FOURCC('s', 'm', 't', 'a'): {
1428 #ifdef __MMFILE_TEST_MODE__
1429 debug_msg("MPEG4: [smta] SIZE: [%lld]Byte\n", chunk_size);
1431 GetSAUTInfoFromSMTATagBox(formatContext, fp, &basic_header);
1434 /* Check smta in user data field to be compatible with android */
1435 case FOURCC('c', 'd', 'i', 's'): {
1436 #ifdef __MMFILE_TEST_MODE__
1437 debug_msg("MPEG4: [smta] SIZE: [%lld]Byte\n", chunk_size);
1439 GetValueFromCDISTagBox(formatContext, fp, &basic_header);
1442 /*/////////////////////////////////////////////////////////////// */
1443 /* Extracting ID3 Tag Data // */
1444 /*/////////////////////////////////////////////////////////////// */
1445 case FOURCC('m', 'e', 't', 'a'): {
1446 #ifdef __MMFILE_TEST_MODE__
1447 debug_msg("MPEG4: [meta] SIZE: [%lld]Byte\n", chunk_size);
1449 GetTagFromMetaBox(formatContext, fp, &basic_header);
1453 case FOURCC('t', 'r', 'a', 'k'): {
1454 #ifdef __MMFILE_TEST_MODE__
1455 debug_msg("MPEG4: [trak] SIZE: [%d]Byte\n", basic_header.size);
1459 case FOURCC('u', 'u', 'i', 'd'): {
1460 #ifdef __MMFILE_TEST_MODE__
1461 debug_msg("MPEG4: [uuid] SIZE: [%d]Byte\n", basic_header.size);
1463 if (!formatContext->is_360) {
1464 unsigned long uuid[4] = {0, };
1466 mmfile_read(fp, (unsigned char *)uuid, sizeof(uuid));
1468 if (mmfile_io_be_uint32(uuid[0]) == 0xffcc8263
1469 && mmfile_io_be_uint32(uuid[1]) == 0xf8554a93
1470 && mmfile_io_be_uint32(uuid[2]) == 0x8814587a
1471 && mmfile_io_be_uint32(uuid[3]) == 0x02521fdd) {
1472 formatContext->is_360 = 1;
1474 ret = mmfile_seek(fp, basic_header.start_offset + basic_header.size, SEEK_SET);
1481 #ifdef __MMFILE_TEST_MODE__
1482 debug_msg("4CC: Not Support [%c%c%c%c]. So skip it. Size [%lld Byte]\n",
1483 ((char *)&basic_header.type)[0], ((char *)&basic_header.type)[1],
1484 ((char *)&basic_header.type)[2], ((char *)&basic_header.type)[3], chunk_size);
1486 ret = mmfile_seek(fp, basic_header.start_offset + chunk_size, SEEK_SET);
1491 if (ret == MMFILE_UTIL_FAIL) {
1492 debug_error("mmfile operation is error\n");
1497 basic_header.start_offset = mmfile_tell(fp);
1505 static char *get_string(const char *buf, int buf_size, int *bytes_written)
1509 char str[512] = {0, };
1512 for (i = 0; i < buf_size; i++) {
1516 if ((q - str) >= (int)sizeof(str) - 1)
1522 if (strlen(str) > 0) {
1523 *bytes_written = strlen(str);
1531 static bool is_numeric(const char *buf, int buf_size)
1536 for (idx = 0; idx < buf_size; idx++) {
1537 if (isdigit((int)buf[idx])) {
1548 char *rtrimN(char *pStr)
1551 pos = strlen(pStr) - 1;
1552 for (; pos >= 0; pos--) {
1553 if (pStr[pos] == 0x20) {
1560 return strdup(pStr);
1563 static bool make_characterset_array(char ***charset_array)
1565 char *locale = MMFileUtilGetLocale(NULL);
1567 *charset_array = calloc(AV_ID3V2_MAX, sizeof(char *));
1569 if (*charset_array == NULL) {
1570 debug_error("calloc failed ");
1576 if (locale != NULL) {
1577 (*charset_array)[AV_ID3V2_ISO_8859] = strdup(locale);
1579 debug_error("get locale failed");
1580 (*charset_array)[AV_ID3V2_ISO_8859] = NULL;
1583 (*charset_array)[AV_ID3V2_UTF16] = strdup("UCS2");
1584 (*charset_array)[AV_ID3V2_UTF16_BE] = strdup("UTF16-BE");
1585 (*charset_array)[AV_ID3V2_UTF8] = strdup("UTF-8");
1590 static bool release_characterset_array(char **charset_array)
1594 for (i = 0; i < AV_ID3V2_MAX; i++) {
1595 if (charset_array[i] != NULL) {
1596 free(charset_array[i]);
1597 charset_array[i] = NULL;
1601 if (charset_array != NULL) {
1602 free(charset_array);
1603 charset_array = NULL;
1609 static void init_content_info(AvFileContentInfo *pInfo)
1611 pInfo->tagV2Info.bTitleMarked = false;
1612 pInfo->tagV2Info.bArtistMarked = false;
1613 pInfo->tagV2Info.bAlbumMarked = false;
1614 pInfo->tagV2Info.bAlbum_ArtistMarked = false;
1615 pInfo->tagV2Info.bYearMarked = false;
1616 pInfo->tagV2Info.bDescriptionMarked = false;
1617 pInfo->tagV2Info.bGenreMarked = false;
1618 pInfo->tagV2Info.bTrackNumMarked = false;
1619 pInfo->tagV2Info.bEncByMarked = false;
1620 pInfo->tagV2Info.bURLMarked = false;
1621 pInfo->tagV2Info.bCopyRightMarked = false;
1622 pInfo->tagV2Info.bOriginArtistMarked = false;
1623 pInfo->tagV2Info.bComposerMarked = false;
1624 pInfo->tagV2Info.bImageMarked = false;
1626 pInfo->tagV2Info.bRecDateMarked = false;
1627 pInfo->tagV2Info.bContentGroupMarked = false;
1629 pInfo->tagV2Info.bUnsyncLyricsMarked = false;
1630 pInfo->tagV2Info.bSyncLyricsMarked = false;
1631 pInfo->tagV2Info.bConductorMarked = false;
1632 pInfo->tagV2Info.bGenreUTF16 = false;
1634 pInfo->imageInfo.bURLInfo = false;
1635 pInfo->imageInfo.pImageBuf = NULL;
1636 pInfo->imageInfo.imageLen = 0;
1640 bool mm_file_id3tag_parse_v110(AvFileContentInfo *pInfo, unsigned char *buffer)
1642 const char *locale = MMFileUtilGetLocale(NULL);
1643 char *pFullStr = NULL;
1645 #ifdef __MMFILE_TEST_MODE__
1646 debug_msg("ID3tag v110--------------------------------------------------------------\n");
1649 if (pInfo->tagV2Info.bTitleMarked == false) {
1650 pFullStr = mmfile_string_convert((const char *)&buffer[3], MP3_ID3_TITLE_LENGTH, "UTF-8", locale, NULL, (unsigned int *)&pInfo->titleLen);
1651 if (pFullStr != NULL) {
1652 pInfo->pTitle = rtrimN(pFullStr);
1656 #ifdef __MMFILE_TEST_MODE__
1657 debug_msg("pInfo->pTitle returned =(%s), pInfo->titleLen(%d)\n", pInfo->pTitle, pInfo->titleLen);
1661 if (pInfo->tagV2Info.bArtistMarked == false) {
1662 pFullStr = mmfile_string_convert((const char *)&buffer[33], MP3_ID3_ARTIST_LENGTH, "UTF-8", locale, NULL, (unsigned int *)&pInfo->artistLen);
1663 if (pFullStr != NULL) {
1664 pInfo->pArtist = rtrimN(pFullStr);
1668 #ifdef __MMFILE_TEST_MODE__
1669 debug_msg("pInfo->pArtist returned =(%s), pInfo->artistLen(%d)\n", pInfo->pArtist, pInfo->artistLen);
1673 if (pInfo->tagV2Info.bAlbumMarked == false) {
1674 pFullStr = mmfile_string_convert((const char *)&buffer[63], MP3_ID3_ALBUM_LENGTH, "UTF-8", locale, NULL, (unsigned int *)&pInfo->albumLen);
1675 if (pFullStr != NULL) {
1676 pInfo->pAlbum = rtrimN(pFullStr);
1680 #ifdef __MMFILE_TEST_MODE__
1681 debug_msg("pInfo->pAlbum returned =(%s), pInfo->albumLen(%d)\n", pInfo->pAlbum, pInfo->albumLen);
1685 if (pInfo->tagV2Info.bYearMarked == false) {
1687 pInfo->pYear = mmfile_string_convert((const char *)&buffer[93], MP3_ID3_YEAR_LENGTH, "UTF-8", locale, NULL, (unsigned int *)&pInfo->yearLen);
1688 #ifdef __MMFILE_TEST_MODE__
1689 debug_msg("pInfo->pYear returned =(%s), pInfo->yearLen(%d)\n", pInfo->pYear, pInfo->yearLen);
1692 if (pInfo->pYear == NULL) { /*Use same logic with ffmpeg*/
1693 pInfo->pYear = get_string((const char *)&buffer[93], MP3_ID3_YEAR_LENGTH, (int *)&pInfo->yearLen);
1694 #ifdef __MMFILE_TEST_MODE__
1695 debug_msg("pInfo->pYear returned =(%s), pInfo->yearLen(%d)\n", pInfo->pYear, pInfo->yearLen);
1700 if (pInfo->tagV2Info.bDescriptionMarked == false) {
1701 pInfo->pComment = mmfile_string_convert((const char *)&buffer[97], MP3_ID3_DESCRIPTION_LENGTH, "UTF-8", locale, NULL, (unsigned int *)&pInfo->commentLen);
1702 #ifdef __MMFILE_TEST_MODE__
1703 debug_msg("pInfo->pComment returned =(%s), pInfo->commentLen(%d)\n", pInfo->pComment, pInfo->commentLen);
1706 if (pInfo->pComment == NULL) { /*Use same logic with ffmpeg*/
1707 pInfo->pComment = get_string((const char *)&buffer[97], MP3_ID3_DESCRIPTION_LENGTH, (int *)&pInfo->commentLen);
1708 #ifdef __MMFILE_TEST_MODE__
1709 debug_msg("pInfo->pComment returned =(%s), pInfo->commentLen(%d)\n", pInfo->pComment, pInfo->commentLen);
1714 if (pInfo->tagV2Info.bTrackNumMarked == false) {
1715 pInfo->pTrackNum = mmfile_malloc(5);
1716 if (pInfo->pTrackNum != NULL) {
1717 pInfo->pTrackNum[4] = 0;
1718 snprintf(pInfo->pTrackNum, 4, "%04d", (int)buffer[126]);
1719 pInfo->tracknumLen = strlen(pInfo->pTrackNum);
1720 #ifdef __MMFILE_TEST_MODE__
1721 debug_msg("pInfo->pTrackNum returned =(%s), pInfo->tracknumLen(%d)\n", pInfo->pTrackNum, pInfo->tracknumLen);
1726 if (pInfo->tagV2Info.bGenreMarked == false) {
1727 pInfo->genre = buffer[127];
1728 #ifdef __MMFILE_TEST_MODE__
1729 debug_msg("pInfo->genre returned genre number (%d)\n", pInfo->genre);
1737 bool mm_file_id3tag_parse_v222(AvFileContentInfo *pInfo, unsigned char *buffer)
1739 unsigned long taglen = 0;
1740 unsigned long needToloopv2taglen;
1741 unsigned long oneFrameLen = 0;
1742 unsigned long v2numOfFrames = 0;
1743 unsigned long curPos = 0;
1745 unsigned char *pExtContent = NULL;
1746 unsigned long purelyFramelen = 0;
1747 unsigned int encodingOffSet = 0;
1748 int inx = 0, realCpyFrameNum = 0,
1749 /*checkImgMimeTypeMax = 0, */checkImgExtMax = 0,
1750 imgstartOffset = 0, tmp = 0;
1752 int textEncodingType = 0;
1754 char **charset_array = NULL;
1756 make_characterset_array(&charset_array);
1758 init_content_info(pInfo);
1760 taglen = pInfo->tagV2Info.tagLen;
1761 needToloopv2taglen = taglen - MP3_TAGv2_HEADER_LEN;
1762 curPos = MP3_TAGv2_HEADER_LEN;
1764 #ifdef __MMFILE_TEST_MODE__
1765 debug_msg("ID3tag v222--------------------------------------------------------------\n");
1767 if (needToloopv2taglen - MP3_TAGv2_22_TXT_HEADER_LEN > MP3_TAGv2_22_TXT_HEADER_LEN) {
1769 while (needToloopv2taglen > MP3_TAGv2_22_TXT_HEADER_LEN) {
1770 if ((buffer[curPos] < '0' || buffer[curPos] > 'Z') || (buffer[curPos + 1] < '0' || buffer[curPos + 1] > 'Z')
1771 || (buffer[curPos + 2] < '0' || buffer[curPos + 2] > 'Z'))
1774 memcpy(CompTmp, &buffer[curPos], 3);
1777 oneFrameLen = MP3_TAGv2_22_TXT_HEADER_LEN;
1778 oneFrameLen += (unsigned long)buffer[3 + curPos] << 16 | (unsigned long)buffer[4 + curPos] << 8
1779 | (unsigned long)buffer[5 + curPos];
1780 if (oneFrameLen > taglen - curPos)
1782 purelyFramelen = oneFrameLen - MP3_TAGv2_22_TXT_HEADER_LEN;
1783 curPos += MP3_TAGv2_22_TXT_HEADER_LEN;
1785 if (oneFrameLen > MP3_TAGv2_22_TXT_HEADER_LEN && purelyFramelen <= taglen - curPos) {
1786 curPos += purelyFramelen;
1788 if (buffer[curPos - purelyFramelen] == 0x00) {
1790 textEncodingType = AV_ID3V2_ISO_8859;
1791 } else if (buffer[curPos - purelyFramelen] == 0x01) {
1793 textEncodingType = AV_ID3V2_UTF16;
1796 /*in order to deliver valid string to MP */
1797 while ((buffer[curPos - purelyFramelen + encodingOffSet] < 0x20) && (encodingOffSet < purelyFramelen))
1800 if (encodingOffSet < purelyFramelen) {
1801 realCpyFrameNum = purelyFramelen - encodingOffSet;
1802 pExtContent = mmfile_malloc(realCpyFrameNum + 3);
1804 if (pExtContent == NULL) {
1805 debug_error("out of memory for pExtContent\n");
1809 memset(pExtContent, '\0', realCpyFrameNum + 3);
1811 memcpy(pExtContent, &buffer[curPos - purelyFramelen + encodingOffSet], purelyFramelen - encodingOffSet);
1813 if (realCpyFrameNum > 0) {
1814 if (strncmp((char *)CompTmp, "TT2", 3) == 0 && pInfo->tagV2Info.bTitleMarked == false) {
1815 pInfo->pTitle = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->titleLen);
1817 #ifdef __MMFILE_TEST_MODE__
1818 debug_msg("pInfo->pTitle returned = (%s), pInfo->titleLen(%d)\n", pInfo->pTitle, pInfo->titleLen);
1820 pInfo->tagV2Info.bTitleMarked = true;
1821 } else if (strncmp((char *)CompTmp, "TP1", 3) == 0 && pInfo->tagV2Info.bArtistMarked == false) {
1822 pInfo->pArtist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->artistLen);
1824 #ifdef __MMFILE_TEST_MODE__
1825 debug_msg("pInfo->pArtist returned = (%s), pInfo->artistLen(%d)\n", pInfo->pArtist, pInfo->artistLen);
1827 pInfo->tagV2Info.bArtistMarked = true;
1828 } else if (strncmp((char *)CompTmp, "TP2", 3) == 0 && pInfo->tagV2Info.bAlbum_ArtistMarked == false) {
1829 pInfo->pAlbum_Artist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->album_artistLen);
1831 #ifdef __MMFILE_TEST_MODE__
1832 debug_msg("pInfo->pAlbum_Artist returned = (%s), pInfo->album_artistLen(%d)\n", pInfo->pAlbum_Artist, pInfo->album_artistLen);
1834 pInfo->tagV2Info.bAlbum_ArtistMarked = true;
1835 } else if (strncmp((char *)CompTmp, "TP3", 3) == 0 && pInfo->tagV2Info.bConductorMarked == false) {
1836 pInfo->pConductor = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->conductorLen);
1838 #ifdef __MMFILE_TEST_MODE__
1839 debug_msg("pInfo->pConductor returned = (%s), pInfo->conductorLen(%d)\n", pInfo->pConductor, pInfo->conductorLen);
1841 pInfo->tagV2Info.bConductorMarked = true;
1842 } else if (strncmp((char *)CompTmp, "TAL", 3) == 0 && pInfo->tagV2Info.bAlbumMarked == false) {
1843 pInfo->pAlbum = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->albumLen);
1845 #ifdef __MMFILE_TEST_MODE__
1846 debug_msg("pInfo->pAlbum returned = (%s), pInfo->albumLen(%d)\n", pInfo->pAlbum, pInfo->albumLen);
1848 pInfo->tagV2Info.bAlbumMarked = true;
1849 } else if (strncmp((char *)CompTmp, "TYE", 3) == 0 && pInfo->tagV2Info.bYearMarked == false) {
1850 pInfo->pYear = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->yearLen);
1852 #ifdef __MMFILE_TEST_MODE__
1853 debug_msg("pInfo->pYear returned = (%s), pInfo->yearLen(%d)\n", pInfo->pYear, pInfo->yearLen);
1855 pInfo->tagV2Info.bYearMarked = true;
1856 } else if (strncmp((char *)CompTmp, "COM", 3) == 0 && pInfo->tagV2Info.bDescriptionMarked == false) {
1857 /*skip language data! */
1858 if (realCpyFrameNum > 4) {
1859 realCpyFrameNum -= 4;
1862 /*pExtContent[tmp+1] value should't have encoding value */
1863 if (pExtContent[tmp] > 0x20 && (pExtContent[tmp - 1] == 0x00 || pExtContent[tmp - 1] == 0x01)) {
1864 if (pExtContent[tmp - 1] == 0x00)
1865 textEncodingType = AV_ID3V2_ISO_8859;
1867 textEncodingType = AV_ID3V2_UTF16;
1869 pInfo->pComment = mmfile_string_convert((char *)&pExtContent[tmp], realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->commentLen);
1871 #ifdef __MMFILE_TEST_MODE__
1872 debug_msg("pInfo->pComment returned = (%s), pInfo->commentLen(%d)\n", pInfo->pComment, pInfo->commentLen);
1874 pInfo->tagV2Info.bDescriptionMarked = true;
1876 #ifdef __MMFILE_TEST_MODE__
1877 debug_msg("mmf_file_id3tag_parse_v222: failed to get Comment Info tmp(%d), purelyFramelen - encodingOffSet(%d)\n", tmp, purelyFramelen - encodingOffSet);
1881 #ifdef __MMFILE_TEST_MODE__
1882 debug_msg("mmf_file_id3tag_parse_v222: Description info too small to parse realCpyFrameNum(%d)\n", realCpyFrameNum);
1887 } else if (strncmp((char *)CompTmp, "TCO", 3) == 0 && pInfo->tagV2Info.bGenreMarked == false) {
1888 pInfo->pGenre = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->genreLen);
1890 #ifdef __MMFILE_TEST_MODE__
1891 debug_msg("pInfo->pGenre returned = (%s), pInfo->genreLen(%d)\n", pInfo->pGenre, pInfo->genreLen);
1894 if ((pInfo->pGenre != NULL) && (pInfo->genreLen > 0)) {
1898 ret = is_numeric(pInfo->pGenre, pInfo->genreLen);
1901 sscanf(pInfo->pGenre, "%d", &int_genre);
1902 #ifdef __MMFILE_TEST_MODE__
1903 debug_msg("genre information is inteager [%d]\n", int_genre);
1906 /*Change int to string */
1907 if ((0 <= int_genre) && (int_genre < GENRE_COUNT - 1)) {
1908 /*save genreinfo like "(123)". mm_file_id3tag_restore_content_info convert it to string*/
1909 char tmp_genre[6] = {0, }; /*ex. "(123)+NULL"*/
1910 int tmp_genre_len = 0;
1912 memset(tmp_genre, 0, 6);
1913 snprintf(tmp_genre, sizeof(tmp_genre), "(%d)", int_genre);
1915 tmp_genre_len = strlen(tmp_genre);
1916 if (tmp_genre_len > 0) {
1917 if (pInfo->pGenre) _FREE_EX(pInfo->pGenre);
1918 pInfo->pGenre = mmfile_malloc(sizeof(char) * (tmp_genre_len + 1));
1919 if (pInfo->pGenre) {
1920 strncpy(pInfo->pGenre, tmp_genre, tmp_genre_len);
1921 pInfo->pGenre[tmp_genre_len] = 0;
1928 pInfo->tagV2Info.bGenreMarked = true;
1929 } else if (strncmp((char *)CompTmp, "TRK", 3) == 0 && pInfo->tagV2Info.bTrackNumMarked == false) {
1930 pInfo->pTrackNum = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->tracknumLen);
1932 #ifdef __MMFILE_TEST_MODE__
1933 debug_msg("pInfo->pTrackNum returned = (%s), pInfo->tracknumLen(%d)\n", pInfo->pTrackNum, pInfo->tracknumLen);
1935 pInfo->tagV2Info.bTrackNumMarked = true;
1936 } else if (strncmp((char *)CompTmp, "TEN", 3) == 0 && pInfo->tagV2Info.bEncByMarked == false) {
1937 pInfo->pEncBy = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->encbyLen);
1939 #ifdef __MMFILE_TEST_MODE__
1940 debug_msg("pInfo->pEncBy returned = (%s), pInfo->encbyLen(%d)\n", pInfo->pEncBy, pInfo->encbyLen);
1942 pInfo->tagV2Info.bEncByMarked = true;
1943 } else if (strncmp((char *)CompTmp, "WXX", 3) == 0 && pInfo->tagV2Info.bURLMarked == false) {
1944 if (realCpyFrameNum > 4) {
1945 /*skip language data! */
1946 realCpyFrameNum -= 4;
1949 /*pExtContent[tmp+1] value should't have null value */
1950 if (pExtContent[tmp] > 0x20 && (pExtContent[tmp - 1] == 0x00 || pExtContent[tmp - 1] == 0x01)) {
1951 if (pExtContent[tmp - 1] == 0x00)
1952 textEncodingType = AV_ID3V2_ISO_8859;
1954 textEncodingType = AV_ID3V2_UTF16;
1956 pInfo->pURL = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->urlLen);
1958 #ifdef __MMFILE_TEST_MODE__
1959 debug_msg("pInfo->pURL returned = (%s), pInfo->urlLen(%d)\n", pInfo->pURL, pInfo->urlLen);
1961 pInfo->tagV2Info.bURLMarked = true;
1963 #ifdef __MMFILE_TEST_MODE__
1964 debug_msg("mmf_file_id3tag_parse_v222: failed to get URL Info tmp(%d), purelyFramelen - encodingOffSet(%d)\n", tmp, purelyFramelen - encodingOffSet);
1968 #ifdef __MMFILE_TEST_MODE__
1969 debug_msg("mmf_file_id3tag_parse_v222: URL info too small to parse realCpyFrameNum(%d)\n", realCpyFrameNum);
1973 } else if (strncmp((char *)CompTmp, "TCR", 3) == 0 && pInfo->tagV2Info.bCopyRightMarked == false) {
1974 pInfo->pCopyright = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->copyrightLen);
1976 #ifdef __MMFILE_TEST_MODE__
1977 debug_msg("pInfo->pCopyright returned = (%s), pInfo->copyrightLen(%d)\n", pInfo->pCopyright, pInfo->copyrightLen);
1979 pInfo->tagV2Info.bCopyRightMarked = true;
1980 } else if (strncmp((char *)CompTmp, "TOA", 3) == 0 && pInfo->tagV2Info.bOriginArtistMarked == false) {
1981 pInfo->pOriginArtist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->originartistLen);
1983 #ifdef __MMFILE_TEST_MODE__
1984 debug_msg("pInfo->pOriginArtist returned = (%s), pInfo->originartistLen(%d)\n", pInfo->pOriginArtist, pInfo->originartistLen);
1986 pInfo->tagV2Info.bOriginArtistMarked = true;
1987 } else if (strncmp((char *)CompTmp, "TCM", 3) == 0 && pInfo->tagV2Info.bComposerMarked == false) {
1988 pInfo->pComposer = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->composerLen);
1990 #ifdef __MMFILE_TEST_MODE__
1991 debug_msg("pInfo->pComposer returned = (%s), pInfo->originartistLen(%d)\n", pInfo->pComposer, pInfo->composerLen);
1993 pInfo->tagV2Info.bComposerMarked = true;
1994 } else if (strncmp((char *)CompTmp, "TRD", 3) == 0 && pInfo->tagV2Info.bRecDateMarked == false) {
1995 pInfo->pRecDate = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->recdateLen);
1997 #ifdef __MMFILE_TEST_MODE__
1998 debug_msg("pInfo->pRecDate returned = (%s), pInfo->recdateLen(%d)\n", pInfo->pRecDate, pInfo->recdateLen);
2000 pInfo->tagV2Info.bRecDateMarked = true;
2001 } else if (strncmp((char *)CompTmp, "PIC", 3) == 0 && pInfo->tagV2Info.bImageMarked == false && realCpyFrameNum <= 2000000) {
2002 if (pExtContent[0] != 0) {
2003 for (inx = 0; inx < MP3_ID3_IMAGE_EXT_MAX_LENGTH; inx++)
2004 pInfo->imageInfo.imageExt[inx] = '\0';/*ini mimetype variable */
2006 while ((checkImgExtMax < MP3_ID3_IMAGE_EXT_MAX_LENGTH - 1) && pExtContent[checkImgExtMax] != '\0') {
2007 pInfo->imageInfo.imageExt[checkImgExtMax] = pExtContent[checkImgExtMax];
2011 #ifdef __MMFILE_TEST_MODE__
2012 debug_msg("mmf_file_id3tag_parse_v222: PIC image's not included to image Extention\n");
2016 imgstartOffset += checkImgExtMax;
2018 if (pExtContent[imgstartOffset] < AV_ID3V2_PICTURE_TYPE_MAX) {
2019 pInfo->imageInfo.pictureType = pExtContent[imgstartOffset];
2021 imgstartOffset++;/*PictureType(1byte) */
2023 if (pExtContent[imgstartOffset] != 0x0) {
2026 int new_dis_len = 0;
2027 char *tmp_desc = NULL;
2030 if (pExtContent[imgstartOffset + cur_pos] == '\0') {
2031 if (realCpyFrameNum < imgstartOffset + cur_pos) {
2032 debug_error("End of APIC Tag %d %d %d\n", realCpyFrameNum, imgstartOffset, cur_pos);
2035 /*check end of image description*/
2036 if ((pExtContent[imgstartOffset + cur_pos + 1] == gTagJPEGHeader[0]) ||
2037 (pExtContent[imgstartOffset + cur_pos + 1] == gTagPNGHeader[0])) {
2038 #ifdef __MMFILE_TEST_MODE__
2039 debug_msg("length of description (%d)", cur_pos);
2048 dis_len = cur_pos + 1;
2050 tmp_desc = mmfile_malloc(sizeof(char) * dis_len);
2052 if (tmp_desc != NULL) {
2053 memcpy(tmp_desc, pExtContent + imgstartOffset, dis_len);
2055 /*convert description*/
2056 pInfo->imageInfo.imageDescription = mmfile_string_convert(tmp_desc, dis_len, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&new_dis_len);
2057 mmfile_free(tmp_desc);
2059 #ifdef __MMFILE_TEST_MODE__
2060 debug_msg("new_desc %s(%d)\n", pInfo->imageInfo.imageDescription, new_dis_len);
2062 pInfo->imageInfo.imgDesLen = new_dis_len; /**/
2065 imgstartOffset += cur_pos;
2067 pInfo->imageInfo.imgDesLen = 0;
2070 if ((pExtContent[imgstartOffset] == '\0') && (realCpyFrameNum - imgstartOffset > 0)) {
2071 imgstartOffset++; /* endofDesceriptionType(1byte) */
2073 while (pExtContent[imgstartOffset] == '\0') { /*some content has useless '\0' in front of picture data */
2077 #ifdef __MMFILE_TEST_MODE__
2078 debug_msg("after scaning imgDescription imgstartOffset(%d) value!\n", imgstartOffset);
2081 if (realCpyFrameNum - imgstartOffset > 0) {
2082 pInfo->imageInfo.imageLen = realCpyFrameNum - imgstartOffset;
2083 pInfo->imageInfo.pImageBuf = mmfile_malloc(pInfo->imageInfo.imageLen + 1);
2085 if (pInfo->imageInfo.pImageBuf != NULL) {
2086 memcpy(pInfo->imageInfo.pImageBuf, pExtContent + imgstartOffset, pInfo->imageInfo.imageLen);
2087 pInfo->imageInfo.pImageBuf[pInfo->imageInfo.imageLen] = 0;
2090 if (IS_INCLUDE_URL(pInfo->imageInfo.imageMIMEType))
2091 pInfo->imageInfo.bURLInfo = true; /*if mimetype is "-->", image date has an URL */
2093 #ifdef __MMFILE_TEST_MODE__
2094 debug_msg("No APIC image!! realCpyFrameNum(%d) - imgstartOffset(%d)\n", realCpyFrameNum, imgstartOffset);
2099 /*checkImgMimeTypeMax = 0;*/
2103 pInfo->tagV2Info.bImageMarked = true;
2110 curPos += purelyFramelen;
2111 if (purelyFramelen != 0)
2112 needToloopv2taglen = MP3_TAGv2_22_TXT_HEADER_LEN;
2115 if (pExtContent) _FREE_EX(pExtContent);
2116 memset(CompTmp, 0, 4);
2117 if (curPos < taglen) {
2118 needToloopv2taglen -= oneFrameLen;
2121 needToloopv2taglen = MP3_TAGv2_22_TXT_HEADER_LEN;
2124 realCpyFrameNum = 0;
2125 textEncodingType = 0;
2131 release_characterset_array(charset_array);
2141 bool mm_file_id3tag_parse_v223(AvFileContentInfo *pInfo, unsigned char *buffer)
2143 unsigned long taglen = 0;
2144 unsigned long needToloopv2taglen;
2145 unsigned long oneFrameLen = 0;
2146 unsigned long v2numOfFrames = 0;
2147 unsigned long curPos = 0;
2149 unsigned char *pExtContent = NULL;
2150 unsigned long purelyFramelen = 0;
2151 unsigned int encodingOffSet = 0;
2152 int inx = 0, realCpyFrameNum = 0, checkImgMimeTypeMax = 0, imgstartOffset = 0, tmp = 0;
2153 int textEncodingType = 0;
2154 char **charset_array = NULL;
2155 const char *MIME_PRFIX = "image/";
2157 make_characterset_array(&charset_array);
2159 init_content_info(pInfo);
2161 taglen = pInfo->tagV2Info.tagLen;
2162 needToloopv2taglen = taglen - MP3_TAGv2_HEADER_LEN;
2163 curPos = MP3_TAGv2_HEADER_LEN;
2165 #ifdef __MMFILE_TEST_MODE__
2166 debug_msg("ID3tag v223--------------------------------------------------------------\n");
2169 /* check Extended Header */
2170 if (buffer[5] & 0x40) {
2171 /* if extended header exists, skip it*/
2172 int extendedHeaderLen = (unsigned long)buffer[10] << 21 | (unsigned long)buffer[11] << 14 | (unsigned long)buffer[12] << 7 | (unsigned long)buffer[13];
2174 #ifdef __MMFILE_TEST_MODE__
2175 debug_msg("--------------- extendedHeaderLen = %d\n", extendedHeaderLen);
2178 if (extendedHeaderLen > (int)(taglen - curPos)) {
2179 debug_error("extended header too long.\n");
2181 curPos += extendedHeaderLen;
2186 if (needToloopv2taglen - MP3_TAGv2_23_TXT_HEADER_LEN > MP3_TAGv2_23_TXT_HEADER_LEN) {
2188 while (needToloopv2taglen > MP3_TAGv2_23_TXT_HEADER_LEN) {
2189 if ((buffer[curPos] < '0' || buffer[curPos] > 'Z') || (buffer[curPos + 1] < '0' || buffer[curPos + 1] > 'Z')
2190 || (buffer[curPos + 2] < '0' || buffer[curPos + 2] > 'Z') || (buffer[curPos + 3] < '0' || buffer[curPos + 3] > 'Z'))
2193 memcpy(CompTmp, &buffer[curPos], 4);
2196 oneFrameLen = MP3_TAGv2_23_TXT_HEADER_LEN;
2197 oneFrameLen += (unsigned long)buffer[4 + curPos] << 24 | (unsigned long)buffer[5 + curPos] << 16
2198 | (unsigned long)buffer[6 + curPos] << 8 | (unsigned long)buffer[7 + curPos];
2200 #ifdef __MMFILE_TEST_MODE__
2201 debug_msg("----------------------------------------------------------------------------------------------------\n");
2204 if (oneFrameLen > taglen - curPos)
2207 purelyFramelen = oneFrameLen - MP3_TAGv2_23_TXT_HEADER_LEN;
2208 curPos += MP3_TAGv2_23_TXT_HEADER_LEN;
2210 if (oneFrameLen > MP3_TAGv2_23_TXT_HEADER_LEN && purelyFramelen <= taglen - curPos) {
2211 curPos += purelyFramelen;
2213 if (IS_ENCODEDBY_UTF16(buffer + (curPos - purelyFramelen))) {
2215 #ifdef __MMFILE_TEST_MODE__
2216 debug_msg("this text string(%s) encoded by UTF16 encodingOffSet(%d)\n", CompTmp, encodingOffSet);
2218 textEncodingType = AV_ID3V2_UTF16;
2219 } else if (IS_ENCODEDBY_UTF16_R(buffer + (curPos - purelyFramelen))) {
2221 #ifdef __MMFILE_TEST_MODE__
2222 debug_msg("this text string(%s) encoded by UTF16 encodingOffSet(%d)\n", CompTmp, encodingOffSet);
2224 textEncodingType = AV_ID3V2_UTF16_BE;
2225 } else if (IS_ENCODEDBY_UTF16(buffer + (curPos - purelyFramelen + 1))) {
2227 #ifdef __MMFILE_TEST_MODE__
2228 debug_msg("this text string(%s) encoded by UTF16 encodingOffSet(%d)\n", CompTmp, encodingOffSet);
2230 textEncodingType = AV_ID3V2_UTF16;
2231 } else if (IS_ENCODEDBY_UTF16_R(buffer + (curPos - purelyFramelen + 1))) {
2233 #ifdef __MMFILE_TEST_MODE__
2234 debug_msg("this text string(%s) encoded by UTF16 encodingOffSet(%d)\n", CompTmp, encodingOffSet);
2236 textEncodingType = AV_ID3V2_UTF16_BE;
2238 if (buffer[curPos - purelyFramelen + encodingOffSet] == 0x00) {
2239 #ifdef __MMFILE_TEST_MODE__
2240 debug_msg("encodingOffset will be set to 1\n");
2245 #ifdef __MMFILE_TEST_MODE__
2246 debug_msg("Finding encodingOffset\n");
2249 while ((buffer[curPos - purelyFramelen + encodingOffSet] < 0x20) && (encodingOffSet < purelyFramelen)) /* text string encoded by ISO-8859-1 */
2252 textEncodingType = AV_ID3V2_ISO_8859;
2253 #ifdef __MMFILE_TEST_MODE__
2254 debug_msg("this text string(%s) encoded by ISO-8859-1 encodingOffSet(%d)\n", CompTmp, encodingOffSet);
2258 if (encodingOffSet < purelyFramelen) {
2259 realCpyFrameNum = purelyFramelen - encodingOffSet;
2260 pExtContent = mmfile_malloc(realCpyFrameNum + 3);
2262 if (pExtContent == NULL) {
2263 debug_msg("pExtContent malloc failed\n");
2267 memset(pExtContent, '\0', realCpyFrameNum + 3);
2269 if (textEncodingType != AV_ID3V2_UTF16 && textEncodingType != AV_ID3V2_UTF16_BE) {
2270 if (CompTmp[0] == 'T' || (strcmp(CompTmp, "APIC") == 0)) {
2271 #ifdef __MMFILE_TEST_MODE__
2272 debug_msg("get the new text ecoding type\n");
2274 textEncodingType = buffer[curPos - purelyFramelen + encodingOffSet - 1];
2278 if (textEncodingType > AV_ID3V2_MAX) {
2279 debug_msg("WRONG ENCOIDNG TYPE [%d], FRAME[%s]\n", textEncodingType, (char *)CompTmp);
2283 memcpy(pExtContent, &buffer[curPos - purelyFramelen + encodingOffSet], purelyFramelen - encodingOffSet);
2284 if (realCpyFrameNum > 0) {
2285 if (strncmp((char *)CompTmp, "TIT2", 4) == 0 && pInfo->tagV2Info.bTitleMarked == false) {
2286 pInfo->pTitle = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->titleLen);
2288 #ifdef __MMFILE_TEST_MODE__
2289 debug_msg("pInfo->pTitle returned = (%s), pInfo->titleLen(%d)\n", pInfo->pTitle, pInfo->titleLen);
2291 pInfo->tagV2Info.bTitleMarked = true;
2293 } else if (strncmp((char *)CompTmp, "TPE1", 4) == 0 && pInfo->tagV2Info.bArtistMarked == false) {
2294 pInfo->pArtist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->artistLen);
2296 #ifdef __MMFILE_TEST_MODE__
2297 debug_msg("pInfo->pArtist returned = (%s), pInfo->artistLen(%d)\n", pInfo->pArtist, pInfo->artistLen);
2299 pInfo->tagV2Info.bArtistMarked = true;
2300 } else if (strncmp((char *)CompTmp, "TPE2", 4) == 0 && pInfo->tagV2Info.bAlbum_ArtistMarked == false) {
2301 pInfo->pAlbum_Artist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->album_artistLen);
2303 #ifdef __MMFILE_TEST_MODE__
2304 debug_msg("pInfo->pAlbum_Artist returned = (%s), pInfo->album_artistLen(%d)\n", pInfo->pAlbum_Artist, pInfo->album_artistLen);
2306 pInfo->tagV2Info.bAlbum_ArtistMarked = true;
2307 } else if (strncmp((char *)CompTmp, "TPE3", 4) == 0 && pInfo->tagV2Info.bConductorMarked == false) {
2308 pInfo->pConductor = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->conductorLen);
2310 #ifdef __MMFILE_TEST_MODE__
2311 debug_msg("pInfo->pConductor returned = (%s), pInfo->conductorLen(%d)\n", pInfo->pConductor, pInfo->conductorLen);
2313 pInfo->tagV2Info.bConductorMarked = true;
2314 } else if (strncmp((char *)CompTmp, "TALB", 4) == 0 && pInfo->tagV2Info.bAlbumMarked == false) {
2315 pInfo->pAlbum = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->albumLen);
2317 #ifdef __MMFILE_TEST_MODE__
2318 debug_msg("pInfo->pAlbum returned = (%s), pInfo->albumLen(%d)\n", pInfo->pAlbum, pInfo->albumLen);
2320 pInfo->tagV2Info.bAlbumMarked = true;
2321 } else if (strncmp((char *)CompTmp, "TYER", 4) == 0 && pInfo->tagV2Info.bYearMarked == false) {
2322 pInfo->pYear = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->yearLen);
2324 #ifdef __MMFILE_TEST_MODE__
2325 debug_msg("pInfo->pYear returned = (%s), pInfo->yearLen(%d)\n", pInfo->pYear, pInfo->yearLen);
2327 pInfo->tagV2Info.bYearMarked = true;
2328 } else if (strncmp((char *)CompTmp, "COMM", 4) == 0 && pInfo->tagV2Info.bDescriptionMarked == false) {
2329 if (realCpyFrameNum > 3) {
2330 realCpyFrameNum -= 3;
2333 /*pExtContent[tmp+1] value should't have encoding value */
2334 if (pExtContent[tmp] == 0x00 || pExtContent[tmp] == 0xFF || pExtContent[tmp] == 0xFE) {
2335 if ((IS_ENCODEDBY_UTF16(pExtContent + tmp) || IS_ENCODEDBY_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 2) {
2336 while ((NEWLINE_OF_UTF16(pExtContent + tmp) || NEWLINE_OF_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 4) {
2337 realCpyFrameNum -= 4;
2341 if (IS_ENCODEDBY_UTF16(pExtContent + tmp) && (realCpyFrameNum > 2)) {
2342 realCpyFrameNum -= 2;
2344 textEncodingType = AV_ID3V2_UTF16;
2345 } else if (IS_ENCODEDBY_UTF16_R(pExtContent + tmp) && (realCpyFrameNum > 2)) {
2346 realCpyFrameNum -= 2;
2348 textEncodingType = AV_ID3V2_UTF16_BE;
2349 } else if (IS_ENCODEDBY_UTF16(pExtContent + tmp + 1) && (realCpyFrameNum > 3)) {
2350 realCpyFrameNum -= 3;
2352 textEncodingType = AV_ID3V2_UTF16;
2353 } else if (IS_ENCODEDBY_UTF16_R(pExtContent + tmp + 1) && (realCpyFrameNum > 3)) {
2354 realCpyFrameNum -= 3;
2356 textEncodingType = AV_ID3V2_UTF16_BE;
2358 #ifdef __MMFILE_TEST_MODE__
2359 debug_msg("pInfo->pComment Never Get Here!!\n");
2363 while ((pExtContent[tmp] < 0x20) && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
2367 textEncodingType = AV_ID3V2_ISO_8859;
2370 #ifdef __MMFILE_TEST_MODE__
2371 debug_msg("tmp(%d) textEncodingType(%d), realCpyFrameNum(%d)\n", tmp, textEncodingType, realCpyFrameNum);
2374 pInfo->pComment = mmfile_string_convert((const char *)&pExtContent[tmp], realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->commentLen);
2376 #ifdef __MMFILE_TEST_MODE__
2377 debug_msg("failed to get Comment Info tmp(%d), purelyFramelen - encodingOffSet(%d)\n", tmp, purelyFramelen - encodingOffSet);
2379 pInfo->commentLen = 0;
2382 #ifdef __MMFILE_TEST_MODE__
2383 debug_msg("Description info too small to parse realCpyFrameNum(%d)\n", realCpyFrameNum);
2385 pInfo->commentLen = 0;
2389 #ifdef __MMFILE_TEST_MODE__
2390 debug_msg("pInfo->pComment returned = (%s), pInfo->commentLen(%d)\n", pInfo->pComment, pInfo->commentLen);
2392 pInfo->tagV2Info.bDescriptionMarked = true;
2393 } else if (strncmp((char *)CompTmp, "SYLT", 4) == 0 && pInfo->tagV2Info.bSyncLyricsMarked == false) {
2396 int copy_start_pos = tmp;
2397 AvSynclyricsInfo *synclyrics_info = NULL;
2398 GList *synclyrics_info_list = NULL;
2400 if (realCpyFrameNum > 5) {
2401 realCpyFrameNum -= 5;
2404 /*pExtContent[tmp+1] value should't have encoding value */
2405 if (pExtContent[tmp] == 0x00 || pExtContent[tmp] == 0xFF || pExtContent[tmp] == 0xFE) {
2406 if ((IS_ENCODEDBY_UTF16(pExtContent + tmp) || IS_ENCODEDBY_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 2) {
2407 while ((NEWLINE_OF_UTF16(pExtContent + tmp) || NEWLINE_OF_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 4) {
2408 realCpyFrameNum -= 4;
2412 if (IS_ENCODEDBY_UTF16(pExtContent + tmp) && (realCpyFrameNum > 2)) {
2413 realCpyFrameNum -= 2;
2415 textEncodingType = AV_ID3V2_UTF16;
2416 } else if (IS_ENCODEDBY_UTF16_R(pExtContent + tmp) && (realCpyFrameNum > 2)) {
2417 realCpyFrameNum -= 2;
2419 textEncodingType = AV_ID3V2_UTF16_BE;
2420 } else if (IS_ENCODEDBY_UTF16(pExtContent + tmp + 1) && (realCpyFrameNum > 3)) {
2421 realCpyFrameNum -= 3;
2423 textEncodingType = AV_ID3V2_UTF16;
2424 } else if (IS_ENCODEDBY_UTF16_R(pExtContent + tmp + 1) && (realCpyFrameNum > 3)) {
2425 realCpyFrameNum -= 3;
2427 textEncodingType = AV_ID3V2_UTF16_BE;
2429 #ifdef __MMFILE_TEST_MODE__
2430 debug_msg("pInfo->pSyncLyrics Never Get Here!!\n");
2434 while ((pExtContent[tmp] < 0x20) && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
2438 textEncodingType = AV_ID3V2_ISO_8859;
2441 #ifdef __MMFILE_TEST_MODE__
2442 debug_msg("tmp(%d) textEncodingType(%d), realCpyFrameNum(%d)\n", tmp, textEncodingType, realCpyFrameNum);
2445 if (realCpyFrameNum < MMFILE_SYNC_LYRIC_INFO_MIN_LEN) {
2446 #ifdef __MMFILE_TEST_MODE__
2447 debug_msg("failed to get Synchronised lyrics Info realCpyFramNum(%d)\n", realCpyFrameNum);
2449 pInfo->syncLyricsNum = 0;
2451 if (textEncodingType == AV_ID3V2_UTF16) {
2452 debug_warning("[AV_ID3V2_UTF16] not implemented\n");
2453 } else if (textEncodingType == AV_ID3V2_UTF16_BE) {
2454 debug_warning("[AV_ID3V2_UTF16_BE] not implemented\n");
2456 for (idx = 0; idx < realCpyFrameNum; idx++) {
2457 if (pExtContent[tmp + idx] == 0x00) {
2458 synclyrics_info = (AvSynclyricsInfo *)malloc(sizeof(AvSynclyricsInfo));
2460 if (synclyrics_info != NULL) {
2461 if (textEncodingType == AV_ID3V2_UTF8) {
2462 synclyrics_info->lyric_info = mmfile_malloc(copy_len + 1);
2463 if (synclyrics_info->lyric_info != NULL) {
2464 memset(synclyrics_info->lyric_info, 0, copy_len + 1);
2465 memcpy(synclyrics_info->lyric_info, pExtContent + copy_start_pos, copy_len);
2466 synclyrics_info->lyric_info[copy_len] = '\0';
2469 synclyrics_info->lyric_info = mmfile_string_convert((const char *)&pExtContent[copy_start_pos], copy_len, "UTF-8", charset_array[AV_ID3V2_ISO_8859], NULL, NULL);
2472 synclyrics_info->time_info = (unsigned long)pExtContent[tmp + idx + 1] << 24 | (unsigned long)pExtContent[tmp + idx + 2] << 16 | (unsigned long)pExtContent[tmp + idx + 3] << 8 | (unsigned long)pExtContent[tmp + idx + 4];
2474 copy_start_pos = tmp + idx + 1;
2475 #ifdef __MMFILE_TEST_MODE__
2476 debug_msg("[%d][%s] idx[%d], copy_len[%d] copy_start_pos[%d]", synclyrics_info->time_info, synclyrics_info->lyric_info, idx, copy_len, copy_start_pos);
2479 synclyrics_info_list = g_list_append(synclyrics_info_list, synclyrics_info);
2484 pInfo->pSyncLyrics = synclyrics_info_list;
2485 pInfo->syncLyricsNum = g_list_length(pInfo->pSyncLyrics);
2489 #ifdef __MMFILE_TEST_MODE__
2490 debug_msg("failed to get Synchronised lyrics Info tmp(%d), purelyFramelen - encodingOffSet(%d)\n", tmp, purelyFramelen - encodingOffSet);
2492 pInfo->syncLyricsNum = 0;
2495 #ifdef __MMFILE_TEST_MODE__
2496 debug_msg("Synchronised lyrics too small to parse realCpyFrameNum(%d)\n", realCpyFrameNum);
2498 pInfo->syncLyricsNum = 0;
2502 #ifdef __MMFILE_TEST_MODE__
2503 debug_msg("pInfo->pSyncLyrics returned = (%s), pInfo->syncLyricsNum(%d)\n", pInfo->pSyncLyrics, pInfo->syncLyricsNum);
2505 pInfo->tagV2Info.bSyncLyricsMarked = true;
2506 } else if (strncmp((char *)CompTmp, "USLT", 4) == 0 && pInfo->tagV2Info.bUnsyncLyricsMarked == false) {
2507 char *lang_info = strndup((char *)pExtContent, 3);
2509 if (realCpyFrameNum > 3) {
2510 realCpyFrameNum -= 3;
2513 /*find start of lyrics */
2515 if (pExtContent[tmp] == 0x00) {
2516 if (pExtContent[tmp + 1] == 0x00) {
2517 realCpyFrameNum -= 2;
2527 /*pExtContent[tmp+1] value should't have encoding value */
2528 #ifdef __MMFILE_TEST_MODE__
2529 debug_msg("tpExtContent[%d] %x\n", tmp, pExtContent[tmp]);
2531 if (pExtContent[tmp] == 0x00 || pExtContent[tmp] == 0xFF || pExtContent[tmp] == 0xFE) {
2532 if ((IS_ENCODEDBY_UTF16(pExtContent + tmp) || IS_ENCODEDBY_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 2) {
2533 while ((NEWLINE_OF_UTF16(pExtContent + tmp) || NEWLINE_OF_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 4) {
2534 realCpyFrameNum -= 4;
2538 if (IS_ENCODEDBY_UTF16(pExtContent + tmp) && (realCpyFrameNum > 2)) {
2539 realCpyFrameNum -= 2;
2541 textEncodingType = AV_ID3V2_UTF16;
2542 } else if (IS_ENCODEDBY_UTF16_R(pExtContent + tmp) && (realCpyFrameNum > 2)) {
2543 realCpyFrameNum -= 2;
2545 textEncodingType = AV_ID3V2_UTF16_BE;
2546 } else if (IS_ENCODEDBY_UTF16(pExtContent + tmp + 1) && (realCpyFrameNum > 3)) {
2547 realCpyFrameNum -= 3;
2549 textEncodingType = AV_ID3V2_UTF16;
2550 } else if (IS_ENCODEDBY_UTF16_R(pExtContent + tmp + 1) && (realCpyFrameNum > 3)) {
2551 realCpyFrameNum -= 3;
2553 textEncodingType = AV_ID3V2_UTF16_BE;
2555 #ifdef __MMFILE_TEST_MODE__
2556 debug_msg("pInfo->pUnsyncLyrics Never Get Here!!\n");
2560 while ((pExtContent[tmp] < 0x20) && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
2564 textEncodingType = AV_ID3V2_ISO_8859;
2567 #ifdef __MMFILE_TEST_MODE__
2568 debug_msg("tmp(%d) textEncodingType(%d), realCpyFrameNum(%d)\n", tmp, textEncodingType, realCpyFrameNum);
2571 char *char_set = NULL;
2572 if (textEncodingType == AV_ID3V2_ISO_8859) {
2573 if (lang_info != NULL && !strcasecmp(lang_info, "KOR")) {
2574 char_set = strdup("EUC-KR");
2576 char_set = mmfile_get_charset((const char *)&pExtContent[tmp]);
2578 _FREE_EX(lang_info);
2581 if (char_set == NULL) {
2582 pInfo->pUnsyncLyrics = mmfile_string_convert((const char *)&pExtContent[tmp], realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->unsynclyricsLen);
2584 pInfo->pUnsyncLyrics = mmfile_string_convert((const char *)&pExtContent[tmp], realCpyFrameNum, "UTF-8", char_set, NULL, (unsigned int *)&pInfo->unsynclyricsLen);
2588 #ifdef __MMFILE_TEST_MODE__
2589 debug_msg("failed to get Unsynchronised lyrics Info tmp(%d), purelyFramelen - encodingOffSet(%d)\n", tmp, purelyFramelen - encodingOffSet);
2591 pInfo->unsynclyricsLen = 0;
2594 #ifdef __MMFILE_TEST_MODE__
2595 debug_msg("Unsynchronised lyrics too small to parse realCpyFrameNum(%d)\n", realCpyFrameNum);
2597 pInfo->unsynclyricsLen = 0;
2601 #ifdef __MMFILE_TEST_MODE__
2602 debug_msg("pInfo->pUnsyncLyrics returned = (%s), pInfo->unsynclyricsLen(%d)\n", pInfo->pUnsyncLyrics, pInfo->unsynclyricsLen);
2604 pInfo->tagV2Info.bUnsyncLyricsMarked = true;
2605 mmfile_free(lang_info);
2606 } else if (strncmp((char *)CompTmp, "TCON", 4) == 0 && pInfo->tagV2Info.bGenreMarked == false) {
2607 pInfo->pGenre = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->genreLen);
2609 #ifdef __MMFILE_TEST_MODE__
2610 debug_msg("pInfo->pGenre returned = (%s), pInfo->genreLen(%d)\n", pInfo->pGenre, pInfo->genreLen);
2613 if ((pInfo->pGenre != NULL) && (pInfo->genreLen > 0)) {
2617 ret = is_numeric(pInfo->pGenre, pInfo->genreLen);
2620 sscanf(pInfo->pGenre, "%d", &int_genre);
2621 #ifdef __MMFILE_TEST_MODE__
2622 debug_msg("genre information is inteager [%d]\n", int_genre);
2625 /*Change int to string */
2626 if ((0 <= int_genre) && (int_genre < GENRE_COUNT - 1)) {
2627 /*save genreinfo like "(123)". mm_file_id3tag_restore_content_info convert it to string*/
2628 char tmp_genre[6] = {0, }; /*ex. "(123)+NULL"*/
2629 int tmp_genre_len = 0;
2631 memset(tmp_genre, 0, 6);
2632 snprintf(tmp_genre, sizeof(tmp_genre), "(%d)", int_genre);
2634 tmp_genre_len = strlen(tmp_genre);
2635 if (tmp_genre_len > 0) {
2636 if (pInfo->pGenre) _FREE_EX(pInfo->pGenre);
2637 pInfo->pGenre = mmfile_malloc(sizeof(char) * (tmp_genre_len + 1));
2638 if (pInfo->pGenre) {
2639 strncpy(pInfo->pGenre, tmp_genre, tmp_genre_len);
2640 pInfo->pGenre[tmp_genre_len] = 0;
2647 pInfo->tagV2Info.bGenreMarked = true;
2648 } else if (strncmp((char *)CompTmp, "TRCK", 4) == 0 && pInfo->tagV2Info.bTrackNumMarked == false) {
2649 pInfo->pTrackNum = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->tracknumLen);
2651 #ifdef __MMFILE_TEST_MODE__
2652 debug_msg("pInfo->pTrackNum returned = (%s), pInfo->tracknumLen(%d)\n", pInfo->pTrackNum, pInfo->tracknumLen);
2654 pInfo->tagV2Info.bTrackNumMarked = true;
2655 } else if (strncmp((char *)CompTmp, "TENC", 4) == 0 && pInfo->tagV2Info.bEncByMarked == false) {
2656 pInfo->pEncBy = mmfile_string_convert((char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->encbyLen);
2658 #ifdef __MMFILE_TEST_MODE__
2659 debug_msg("pInfo->pEncBy returned = (%s), pInfo->encbyLen(%d)\n", pInfo->pEncBy, pInfo->encbyLen);
2661 pInfo->tagV2Info.bEncByMarked = true;
2662 } else if (strncmp((char *)CompTmp, "WXXX", 4) == 0 && pInfo->tagV2Info.bURLMarked == false) {
2663 pInfo->pURL = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->urlLen);
2665 #ifdef __MMFILE_TEST_MODE__
2666 debug_msg("pInfo->pURL returned = (%s), pInfo->urlLen(%d)\n", pInfo->pURL, pInfo->urlLen);
2668 pInfo->tagV2Info.bURLMarked = true;
2669 } else if (strncmp((char *)CompTmp, "TCOP", 4) == 0 && pInfo->tagV2Info.bCopyRightMarked == false) {
2670 pInfo->pCopyright = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->copyrightLen);
2672 #ifdef __MMFILE_TEST_MODE__
2673 debug_msg("pInfo->pCopyright returned = (%s), pInfo->copyrightLen(%d)\n", pInfo->pCopyright, pInfo->copyrightLen);
2675 pInfo->tagV2Info.bCopyRightMarked = true;
2676 } else if (strncmp((char *)CompTmp, "TOPE", 4) == 0 && pInfo->tagV2Info.bOriginArtistMarked == false) {
2677 pInfo->pOriginArtist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->originartistLen);
2679 #ifdef __MMFILE_TEST_MODE__
2680 debug_msg("pInfo->pOriginArtist returned = (%s), pInfo->originartistLen(%d)\n", pInfo->pOriginArtist, pInfo->originartistLen);
2682 pInfo->tagV2Info.bOriginArtistMarked = true;
2683 } else if (strncmp((char *)CompTmp, "TCOM", 4) == 0 && pInfo->tagV2Info.bComposerMarked == false) {
2684 pInfo->pComposer = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->composerLen);
2686 #ifdef __MMFILE_TEST_MODE__
2687 debug_msg("pInfo->pComposer returned = (%s), pInfo->composerLen(%d)\n", pInfo->pComposer, pInfo->composerLen);
2689 pInfo->tagV2Info.bComposerMarked = true;
2690 } else if (strncmp((char *)CompTmp, "TRDA", 4) == 0 && pInfo->tagV2Info.bRecDateMarked == false) {
2691 pInfo->pRecDate = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->recdateLen);
2693 #ifdef __MMFILE_TEST_MODE__
2694 debug_msg("pInfo->pRecDate returned = (%s), pInfo->recdateLen(%d)\n", pInfo->pRecDate, pInfo->recdateLen);
2696 pInfo->tagV2Info.bRecDateMarked = true;
2697 } else if (strncmp((char *)CompTmp, "APIC", 4) == 0 && pInfo->tagV2Info.bImageMarked == false && realCpyFrameNum <= 2000000) {
2698 debug_msg("text encoding %d \n", textEncodingType);
2700 if (pExtContent[0] != '\0') {
2701 for (inx = 0; inx < MP3_ID3_IMAGE_MIME_TYPE_MAX_LENGTH - 1; inx++)
2702 pInfo->imageInfo.imageMIMEType[inx] = '\0';/*ini mimetype variable */
2704 while ((checkImgMimeTypeMax < MP3_ID3_IMAGE_MIME_TYPE_MAX_LENGTH - 1) && pExtContent[checkImgMimeTypeMax] != '\0') {
2705 pInfo->imageInfo.imageMIMEType[checkImgMimeTypeMax] = pExtContent[checkImgMimeTypeMax];
2706 checkImgMimeTypeMax++;
2708 pInfo->imageInfo.imgMimetypeLen = checkImgMimeTypeMax;
2710 pInfo->imageInfo.imgMimetypeLen = 0;
2711 #ifdef __MMFILE_TEST_MODE__
2712 debug_msg("APIC image's not included to MIME type\n");
2716 imgstartOffset += checkImgMimeTypeMax;
2718 if (strncmp(pInfo->imageInfo.imageMIMEType, MIME_PRFIX, strlen(MIME_PRFIX)) != 0) {
2719 pInfo->imageInfo.imgMimetypeLen = 0;
2720 debug_error("APIC NOT VALID");
2724 if ((pExtContent[imgstartOffset] == '\0') && (realCpyFrameNum - imgstartOffset > 0)) {
2725 imgstartOffset++;/*endofMIME(1byte) */
2726 #ifdef __MMFILE_TEST_MODE__
2727 debug_msg("after scaning Mime type imgstartOffset(%d) value!\n", imgstartOffset);
2730 if (pExtContent[imgstartOffset] < AV_ID3V2_PICTURE_TYPE_MAX) {
2731 pInfo->imageInfo.pictureType = pExtContent[imgstartOffset];
2733 #ifdef __MMFILE_TEST_MODE__
2734 debug_msg("APIC image has invalid picture type(0x%x)\n", pExtContent[imgstartOffset]);
2737 imgstartOffset++;/*PictureType(1byte) */
2738 #ifdef __MMFILE_TEST_MODE__
2739 debug_msg("after scaning PictureType imgstartOffset(%d) value!\n", imgstartOffset);
2742 if (pExtContent[imgstartOffset] != 0x0) {
2745 int new_dis_len = 0;
2746 char *tmp_desc = NULL;
2749 if (pExtContent[imgstartOffset + cur_pos] == '\0') {
2750 if (realCpyFrameNum < imgstartOffset + cur_pos) {
2751 debug_error("End of APIC Tag %d %d %d\n", realCpyFrameNum, imgstartOffset, cur_pos);
2754 /*check end of image description*/
2755 if ((pExtContent[imgstartOffset + cur_pos + 1] == gTagJPEGHeader[0]) ||
2756 (pExtContent[imgstartOffset + cur_pos + 1] == gTagPNGHeader[0])) {
2757 #ifdef __MMFILE_TEST_MODE__
2758 debug_msg("length of description (%d)", cur_pos);
2767 dis_len = cur_pos + 1;
2769 tmp_desc = mmfile_malloc(sizeof(char) * dis_len);
2770 memcpy(tmp_desc, pExtContent + imgstartOffset, dis_len);
2772 /*convert description*/
2773 pInfo->imageInfo.imageDescription = mmfile_string_convert(tmp_desc, dis_len, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&new_dis_len);
2774 #ifdef __MMFILE_TEST_MODE__
2775 debug_msg("new_desc %s(%d)\n", pInfo->imageInfo.imageDescription, new_dis_len);
2777 mmfile_free(tmp_desc);
2779 pInfo->imageInfo.imgDesLen = new_dis_len; /**/
2780 imgstartOffset += cur_pos;
2782 pInfo->imageInfo.imgDesLen = 0;
2783 #ifdef __MMFILE_TEST_MODE__
2784 debug_msg("APIC image's not included to Description!!!\n");
2788 if ((pExtContent[imgstartOffset] == '\0') && (realCpyFrameNum - imgstartOffset > 0)) {
2789 imgstartOffset++; /* endofDesceriptionType(1byte) */
2791 while (pExtContent[imgstartOffset] == '\0') { /*some content has useless '\0' in front of picture data */
2795 #ifdef __MMFILE_TEST_MODE__
2796 debug_msg("after scaning imgDescription imgstartOffset(%d) value!\n", imgstartOffset);
2799 if (realCpyFrameNum - imgstartOffset > 0) {
2800 pInfo->imageInfo.imageLen = realCpyFrameNum - imgstartOffset;
2801 pInfo->imageInfo.pImageBuf = mmfile_malloc(pInfo->imageInfo.imageLen + 1);
2803 if (pInfo->imageInfo.pImageBuf != NULL) {
2804 memcpy(pInfo->imageInfo.pImageBuf, pExtContent + imgstartOffset, pInfo->imageInfo.imageLen);
2805 pInfo->imageInfo.pImageBuf[pInfo->imageInfo.imageLen] = 0;
2808 if (IS_INCLUDE_URL(pInfo->imageInfo.imageMIMEType))
2809 pInfo->imageInfo.bURLInfo = true; /*if mimetype is "-->", image date has an URL */
2811 #ifdef __MMFILE_TEST_MODE__
2812 debug_msg("No APIC image!! realCpyFrameNum(%d) - imgstartOffset(%d)\n", realCpyFrameNum, imgstartOffset);
2815 #ifdef __MMFILE_TEST_MODE__
2816 debug_msg("pInfo->imageInfo.imageLen(%d), imgstartOffset(%d)!\n", pInfo->imageInfo.imageLen, imgstartOffset);
2819 #ifdef __MMFILE_TEST_MODE__
2820 debug_msg("pExtContent[imgstartOffset](%d) value should setted NULL value for end of description! realCpyFrameNum - imgstartOffset(%d)\n",
2821 pExtContent[imgstartOffset], realCpyFrameNum - imgstartOffset);
2825 #ifdef __MMFILE_TEST_MODE__
2826 debug_msg("pExtContent[imgstartOffset](%d) value should setted NULL value for end of mimetype! realCpyFrameNum - imgstartOffset(%d)\n",
2827 pExtContent[imgstartOffset], realCpyFrameNum - imgstartOffset);
2831 checkImgMimeTypeMax = 0;
2834 pInfo->tagV2Info.bImageMarked = true;
2837 #ifdef __MMFILE_TEST_MODE__
2838 debug_msg("CompTmp(%s) This Frame ID currently not Supports!!\n", CompTmp);
2844 #ifdef __MMFILE_TEST_MODE__
2845 debug_msg("All of the pExtContent Values are NULL\n");
2849 curPos += purelyFramelen;
2850 if (purelyFramelen != 0)
2851 needToloopv2taglen = MP3_TAGv2_23_TXT_HEADER_LEN;
2852 #ifdef __MMFILE_TEST_MODE__
2853 debug_msg("This Frame's size is Zero! purelyFramelen(%d)\n", purelyFramelen);
2857 if (pExtContent) _FREE_EX(pExtContent);
2858 memset(CompTmp, 0, 4);
2860 if (curPos < taglen) {
2861 needToloopv2taglen -= oneFrameLen;
2864 needToloopv2taglen = MP3_TAGv2_23_TXT_HEADER_LEN;
2867 realCpyFrameNum = 0;
2868 textEncodingType = 0;
2874 release_characterset_array(charset_array);
2884 bool mm_file_id3tag_parse_v224(AvFileContentInfo *pInfo, unsigned char *buffer)
2886 unsigned long taglen = 0;
2887 unsigned long needToloopv2taglen;
2888 unsigned long oneFrameLen = 0;
2889 unsigned long v2numOfFrames = 0;
2890 unsigned long curPos = 0;
2892 unsigned char *pExtContent = NULL;
2893 unsigned long purelyFramelen = 0;
2894 unsigned int encodingOffSet = 0;
2895 int inx = 0, realCpyFrameNum = 0, checkImgMimeTypeMax = 0, imgstartOffset = 0, tmp = 0;
2896 int textEncodingType = 0;
2897 char **charset_array = NULL;
2898 const char *MIME_PRFIX = "image/";
2900 make_characterset_array(&charset_array);
2902 init_content_info(pInfo);
2904 taglen = pInfo->tagV2Info.tagLen;
2905 needToloopv2taglen = taglen - MP3_TAGv2_HEADER_LEN;
2906 curPos = MP3_TAGv2_HEADER_LEN;
2908 #ifdef __MMFILE_TEST_MODE__
2909 debug_msg("ID3tag v224--------------------------------------------------------------\n");
2912 /* check Extended Header */
2913 if (buffer[5] & 0x40) {
2914 /* if extended header exists, skip it*/
2915 int extendedHeaderLen = (unsigned long)buffer[10] << 21 | (unsigned long)buffer[11] << 14 | (unsigned long)buffer[12] << 7 | (unsigned long)buffer[13];
2917 #ifdef __MMFILE_TEST_MODE__
2918 debug_msg("--------------- extendedHeaderLen = %d\n", extendedHeaderLen);
2921 if (extendedHeaderLen > (int)(taglen - curPos)) {
2922 debug_error("extended header too long.\n");
2924 curPos += extendedHeaderLen;
2928 if (needToloopv2taglen - MP3_TAGv2_23_TXT_HEADER_LEN > MP3_TAGv2_23_TXT_HEADER_LEN) {
2930 while (needToloopv2taglen > MP3_TAGv2_23_TXT_HEADER_LEN) {
2931 if ((buffer[curPos] < '0' || buffer[curPos] > 'Z') || (buffer[curPos + 1] < '0' || buffer[curPos + 1] > 'Z')
2932 || (buffer[curPos + 2] < '0' || buffer[curPos + 2] > 'Z') || (buffer[curPos + 3] < '0' || buffer[curPos + 3] > 'Z'))
2935 memcpy(CompTmp, &buffer[curPos], 4);
2938 oneFrameLen = MP3_TAGv2_23_TXT_HEADER_LEN;
2939 oneFrameLen += (unsigned long)buffer[4 + curPos] << 21 | (unsigned long)buffer[5 + curPos] << 14
2940 | (unsigned long)buffer[6 + curPos] << 7 | (unsigned long)buffer[7 + curPos];
2941 if (oneFrameLen > taglen - curPos)
2944 purelyFramelen = oneFrameLen - MP3_TAGv2_23_TXT_HEADER_LEN;
2945 curPos += MP3_TAGv2_23_TXT_HEADER_LEN;
2947 #ifdef __MMFILE_TEST_MODE__
2948 debug_msg("-----------------------------------------------------------------------------------\n");
2951 if (oneFrameLen > MP3_TAGv2_23_TXT_HEADER_LEN && purelyFramelen <= taglen - curPos) {
2952 curPos += purelyFramelen;
2954 /*in case of UTF 16 encoding */
2955 /*buffer+(curPos-purelyFramelen) data should '0x01' but in order to expansion, we don't accurately check the value. */
2956 if (IS_ENCODEDBY_UTF16(buffer + (curPos - purelyFramelen))) {
2958 textEncodingType = AV_ID3V2_UTF16;
2959 } else if (IS_ENCODEDBY_UTF16_R(buffer + (curPos - purelyFramelen))) {
2961 textEncodingType = AV_ID3V2_UTF16_BE;
2962 } else if (IS_ENCODEDBY_UTF16(buffer + (curPos - purelyFramelen + 1))) {
2964 textEncodingType = AV_ID3V2_UTF16;
2965 } else if (IS_ENCODEDBY_UTF16_R(buffer + (curPos - purelyFramelen + 1))) {
2967 textEncodingType = AV_ID3V2_UTF16_BE;
2969 /*in case of UTF-16 BE encoding */
2970 if (buffer[curPos - purelyFramelen] == 0x02) {
2972 while ((buffer[curPos - purelyFramelen + encodingOffSet] == '\0') && (encodingOffSet < purelyFramelen))
2973 encodingOffSet++;/*null skip! */
2974 textEncodingType = AV_ID3V2_UTF16_BE;
2976 /*in case of UTF8 encoding */
2977 else if (buffer[curPos - purelyFramelen] == 0x03) {
2979 while ((buffer[curPos - purelyFramelen + encodingOffSet] == '\0') && (encodingOffSet < purelyFramelen))
2980 encodingOffSet++;/*null skip! */
2981 textEncodingType = AV_ID3V2_UTF8;
2983 /*in case of ISO-8859-1 encoding */
2985 /*buffer+(curPos-purelyFramelen) data should 0x00 but in order to expansion, we don't accurately check the value. */
2987 while ((buffer[curPos - purelyFramelen + encodingOffSet] < 0x20) && (encodingOffSet < purelyFramelen))
2988 encodingOffSet++;/*less than 0x20 value skip! */
2989 textEncodingType = AV_ID3V2_ISO_8859;
2993 if (encodingOffSet < purelyFramelen) {
2994 realCpyFrameNum = purelyFramelen - encodingOffSet;
2995 pExtContent = mmfile_malloc(realCpyFrameNum + 3);
2997 if (pExtContent == NULL) {
2998 debug_error("out of memoryu for id3tag parse\n");
3002 memset(pExtContent, '\0', realCpyFrameNum + 3);
3004 if (textEncodingType != AV_ID3V2_UTF16 && textEncodingType != AV_ID3V2_UTF16_BE) {
3005 if (CompTmp[0] == 'T' || (strcmp(CompTmp, "APIC") == 0)) {
3006 #ifdef __MMFILE_TEST_MODE__
3007 debug_msg("get the new text ecoding type\n");
3009 textEncodingType = buffer[curPos - purelyFramelen + encodingOffSet - 1];
3013 if (textEncodingType > AV_ID3V2_MAX) {
3014 debug_msg("WRONG ENCOIDNG TYPE [%d], FRAME[%s]\n", textEncodingType, (char *)CompTmp);
3018 memcpy(pExtContent, &buffer[curPos - purelyFramelen + encodingOffSet], purelyFramelen - encodingOffSet);
3020 if (realCpyFrameNum > 0) {
3021 if (strncmp((char *)CompTmp, "TIT2", 4) == 0 && pInfo->tagV2Info.bTitleMarked == false) {
3022 if (textEncodingType == AV_ID3V2_UTF8) {
3023 pInfo->pTitle = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3024 if (pInfo->pTitle) {
3025 memcpy(pInfo->pTitle, pExtContent, realCpyFrameNum);
3026 pInfo->pTitle[realCpyFrameNum] = '\0';
3027 /*string copy with '\0'*/
3028 pInfo->titleLen = realCpyFrameNum;
3029 _STRNCPY_EX(pInfo->pTitle, pExtContent, pInfo->titleLen);
3032 pInfo->pTitle = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->titleLen);
3035 #ifdef __MMFILE_TEST_MODE__
3036 debug_msg("pInfo->pTitle returned = (%s), pInfo->titleLen(%d)\n", pInfo->pTitle, pInfo->titleLen);
3038 pInfo->tagV2Info.bTitleMarked = true;
3040 } else if (strncmp((char *)CompTmp, "TPE1", 4) == 0 && pInfo->tagV2Info.bArtistMarked == false) {
3041 if (textEncodingType == AV_ID3V2_UTF8) {
3042 pInfo->pArtist = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3043 if (pInfo->pArtist) {
3044 memcpy(pInfo->pArtist, pExtContent, realCpyFrameNum);
3045 pInfo->pArtist[realCpyFrameNum] = '\0';
3046 /*string copy with '\0'*/
3047 pInfo->artistLen = realCpyFrameNum;
3048 _STRNCPY_EX(pInfo->pArtist, pExtContent, pInfo->artistLen);
3051 pInfo->pArtist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->artistLen);
3054 #ifdef __MMFILE_TEST_MODE__
3055 debug_msg("pInfo->pArtist returned = (%s), pInfo->artistLen(%d)\n", pInfo->pArtist, pInfo->artistLen);
3057 pInfo->tagV2Info.bArtistMarked = true;
3058 } else if (strncmp((char *)CompTmp, "TPE2", 4) == 0 && pInfo->tagV2Info.bAlbum_ArtistMarked == false) {
3059 if (textEncodingType == AV_ID3V2_UTF8) {
3060 pInfo->pAlbum_Artist = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3061 if (pInfo->pAlbum_Artist) {
3062 memcpy(pInfo->pAlbum_Artist, pExtContent, realCpyFrameNum);
3063 pInfo->pAlbum_Artist[realCpyFrameNum] = '\0';
3064 /*string copy with '\0'*/
3065 pInfo->album_artistLen = realCpyFrameNum;
3066 _STRNCPY_EX(pInfo->pAlbum_Artist, pExtContent, pInfo->album_artistLen);
3069 pInfo->pAlbum_Artist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->album_artistLen);
3072 #ifdef __MMFILE_TEST_MODE__
3073 debug_msg("pInfo->pAlbum_Artist returned = (%s), pInfo->album_artistLen(%d)\n", pInfo->pAlbum_Artist, pInfo->album_artistLen);
3075 pInfo->tagV2Info.bAlbum_ArtistMarked = true;
3076 } else if (strncmp((char *)CompTmp, "TPE3", 4) == 0 && pInfo->tagV2Info.bConductorMarked == false) {
3077 if (textEncodingType == AV_ID3V2_UTF8) {
3078 pInfo->pConductor = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3079 if (pInfo->pConductor) {
3080 memcpy(pInfo->pConductor, pExtContent, realCpyFrameNum);
3081 pInfo->pConductor[realCpyFrameNum] = '\0';
3082 /*string copy with '\0'*/
3083 pInfo->conductorLen = realCpyFrameNum;
3084 _STRNCPY_EX(pInfo->pConductor, pExtContent, pInfo->conductorLen);
3087 pInfo->pConductor = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->conductorLen);
3090 #ifdef __MMFILE_TEST_MODE__
3091 debug_msg("pInfo->pConductor returned = (%s), pInfo->conductorLen(%d)\n", pInfo->pConductor, pInfo->conductorLen);
3093 pInfo->tagV2Info.bConductorMarked = true;
3094 } else if (strncmp((char *)CompTmp, "TALB", 4) == 0 && pInfo->tagV2Info.bAlbumMarked == false) {
3095 if (textEncodingType == AV_ID3V2_UTF8) {
3096 pInfo->pAlbum = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3097 if (pInfo->pAlbum) {
3098 memcpy(pInfo->pAlbum, pExtContent, realCpyFrameNum);
3099 pInfo->pAlbum[realCpyFrameNum] = '\0';
3100 /*string copy with '\0'*/
3101 pInfo->albumLen = realCpyFrameNum;
3102 _STRNCPY_EX(pInfo->pAlbum, pExtContent, pInfo->albumLen);
3105 pInfo->pAlbum = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->albumLen);
3108 #ifdef __MMFILE_TEST_MODE__
3109 debug_msg("pInfo->pAlbum returned = (%s), pInfo->albumLen(%d)\n", pInfo->pAlbum, pInfo->albumLen);
3111 pInfo->tagV2Info.bAlbumMarked = true;
3112 } else if (strncmp((char *)CompTmp, "TYER", 4) == 0 && pInfo->tagV2Info.bYearMarked == false) { /*TODO. TYER is replaced by the TDRC. but many files use TYER in v2.4 */
3113 if (textEncodingType == AV_ID3V2_UTF8) {
3114 pInfo->pYear = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3116 memcpy(pInfo->pYear, pExtContent, realCpyFrameNum);
3117 pInfo->pYear[realCpyFrameNum] = '\0';
3118 /*string copy with '\0'*/
3119 pInfo->yearLen = realCpyFrameNum;
3120 _STRNCPY_EX(pInfo->pYear, pExtContent, pInfo->yearLen);
3123 pInfo->pYear = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->yearLen);
3126 #ifdef __MMFILE_TEST_MODE__
3127 debug_msg("pInfo->pYear returned = (%s), pInfo->yearLen(%d)\n", pInfo->pYear, pInfo->yearLen);
3129 pInfo->tagV2Info.bYearMarked = true;
3130 } else if (strncmp((char *)CompTmp, "COMM", 4) == 0 && pInfo->tagV2Info.bDescriptionMarked == false) {
3131 if (realCpyFrameNum > 3) {
3132 realCpyFrameNum -= 3;
3135 if (textEncodingType == AV_ID3V2_UTF16 || textEncodingType == AV_ID3V2_UTF16_BE) {
3136 while ((NEWLINE_OF_UTF16(pExtContent + tmp) || NEWLINE_OF_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 4) {
3137 realCpyFrameNum -= 4;
3141 if ((IS_ENCODEDBY_UTF16(pExtContent + tmp) || IS_ENCODEDBY_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 2) {
3142 realCpyFrameNum -= 2;
3144 textEncodingType = AV_ID3V2_UTF16;
3146 #ifdef __MMFILE_TEST_MODE__
3147 debug_msg("pInfo->pComment Never Get Here!!\n");
3150 } else if (textEncodingType == AV_ID3V2_UTF8) {
3151 while (pExtContent[tmp] < 0x20 && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
3155 textEncodingType = AV_ID3V2_UTF8;
3157 while (pExtContent[tmp] < 0x20 && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
3161 textEncodingType = AV_ID3V2_ISO_8859;
3164 #ifdef __MMFILE_TEST_MODE__
3165 debug_msg("tmp(%d) textEncodingType(%d), realCpyFrameNum(%d)\n", tmp, textEncodingType, realCpyFrameNum);
3168 if (textEncodingType == AV_ID3V2_UTF8) {
3169 pInfo->pComment = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3170 if (pInfo->pComment) {
3171 memset(pInfo->pComment, 0, (realCpyFrameNum + 2));
3172 memcpy(pInfo->pComment, pExtContent + tmp, realCpyFrameNum);
3173 pInfo->pComment[realCpyFrameNum] = '\0';
3174 /*string copy with '\0'*/
3175 pInfo->commentLen = realCpyFrameNum;
3176 _STRNCPY_EX(pInfo->pComment, pExtContent, pInfo->commentLen);
3179 pInfo->pComment = mmfile_string_convert((const char *)&pExtContent[tmp], realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->commentLen);
3182 #ifdef __MMFILE_TEST_MODE__
3183 debug_msg("Description info too small to parse realCpyFrameNum(%d)\n", realCpyFrameNum);
3189 #ifdef __MMFILE_TEST_MODE__
3190 debug_msg("pInfo->pComment returned = (%s), pInfo->commentLen(%d)\n", pInfo->pComment, pInfo->commentLen);
3192 pInfo->tagV2Info.bDescriptionMarked = true;
3193 } else if (strncmp((char *)CompTmp, "SYLT", 4) == 0 && pInfo->tagV2Info.bSyncLyricsMarked == false) {
3196 int copy_start_pos = tmp;
3197 AvSynclyricsInfo *synclyrics_info = NULL;
3198 GList *synclyrics_info_list = NULL;
3200 if (realCpyFrameNum > 5) {
3201 realCpyFrameNum -= 5;
3204 if (textEncodingType == AV_ID3V2_UTF16 || textEncodingType == AV_ID3V2_UTF16_BE) {
3205 while ((NEWLINE_OF_UTF16(pExtContent + tmp) || NEWLINE_OF_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 4) {
3206 realCpyFrameNum -= 4;
3210 if ((IS_ENCODEDBY_UTF16(pExtContent + tmp) || IS_ENCODEDBY_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 2) {
3211 realCpyFrameNum -= 2;
3213 textEncodingType = AV_ID3V2_UTF16;
3215 #ifdef __MMFILE_TEST_MODE__
3216 debug_msg("pInfo->pSyncLyrics Never Get Here!!\n");
3219 } else if (textEncodingType == AV_ID3V2_UTF8) {
3220 while (pExtContent[tmp] < 0x20 && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
3224 textEncodingType = AV_ID3V2_UTF8;
3226 while (pExtContent[tmp] < 0x20 && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
3230 textEncodingType = AV_ID3V2_ISO_8859;
3233 #ifdef __MMFILE_TEST_MODE__
3234 debug_msg("tmp(%d) textEncodingType(%d), realCpyFrameNum(%d)\n", tmp, textEncodingType, realCpyFrameNum);
3237 if (realCpyFrameNum < MMFILE_SYNC_LYRIC_INFO_MIN_LEN) {
3238 #ifdef __MMFILE_TEST_MODE__
3239 debug_msg("failed to get Synchronised lyrics Info realCpyFramNum(%d)\n", realCpyFrameNum);
3241 pInfo->syncLyricsNum = 0;
3243 if (textEncodingType == AV_ID3V2_UTF16) {
3244 debug_warning("[AV_ID3V2_UTF16] not implemented\n");
3245 } else if (textEncodingType == AV_ID3V2_UTF16_BE) {
3246 debug_warning("[AV_ID3V2_UTF16_BE] not implemented\n");
3248 for (idx = 0; idx < realCpyFrameNum; idx++) {
3249 if (pExtContent[tmp + idx] == 0x00) {
3250 synclyrics_info = (AvSynclyricsInfo *)malloc(sizeof(AvSynclyricsInfo));
3252 if (textEncodingType == AV_ID3V2_UTF8) {
3253 synclyrics_info->lyric_info = mmfile_malloc(copy_len + 1);
3254 if (synclyrics_info->lyric_info) {
3255 memset(synclyrics_info->lyric_info, 0, copy_len + 1);
3256 memcpy(synclyrics_info->lyric_info, pExtContent + copy_start_pos, copy_len);
3257 synclyrics_info->lyric_info[copy_len] = '\0';
3260 synclyrics_info->lyric_info = mmfile_string_convert((const char *)&pExtContent[copy_start_pos], copy_len, "UTF-8", charset_array[textEncodingType], NULL, NULL);
3263 synclyrics_info->time_info = (unsigned long)pExtContent[tmp + idx + 1] << 24 | (unsigned long)pExtContent[tmp + idx + 2] << 16 | (unsigned long)pExtContent[tmp + idx + 3] << 8 | (unsigned long)pExtContent[tmp + idx + 4];
3265 copy_start_pos = tmp + idx + 1;
3266 #ifdef __MMFILE_TEST_MODE__
3267 debug_msg("[%d][%s] idx[%d], copy_len[%d] copy_start_pos[%d]", synclyrics_info->time_info, synclyrics_info->lyric_info, idx, copy_len, copy_start_pos);
3270 synclyrics_info_list = g_list_append(synclyrics_info_list, synclyrics_info);
3274 pInfo->pSyncLyrics = synclyrics_info_list;
3275 pInfo->syncLyricsNum = g_list_length(pInfo->pSyncLyrics);
3279 #ifdef __MMFILE_TEST_MODE__
3280 debug_msg("SyncLyrics info too small to parse realCpyFrameNum(%d)\n", realCpyFrameNum);
3285 pInfo->tagV2Info.bSyncLyricsMarked = true;
3286 } else if (strncmp((char *)CompTmp, "USLT", 4) == 0 && pInfo->tagV2Info.bUnsyncLyricsMarked == false) {
3287 if (realCpyFrameNum > 3) {
3288 realCpyFrameNum -= 3;
3291 if (textEncodingType == AV_ID3V2_UTF16 || textEncodingType == AV_ID3V2_UTF16_BE) {
3292 while ((NEWLINE_OF_UTF16(pExtContent + tmp) || NEWLINE_OF_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 4) {
3293 realCpyFrameNum -= 4;
3297 if ((IS_ENCODEDBY_UTF16(pExtContent + tmp) || IS_ENCODEDBY_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 2) {
3298 realCpyFrameNum -= 2;
3300 textEncodingType = AV_ID3V2_UTF16;
3302 #ifdef __MMFILE_TEST_MODE__
3303 debug_msg("pInfo->pUnsyncLyrics Never Get Here!!\n");
3306 } else if (textEncodingType == AV_ID3V2_UTF8) {
3307 while (pExtContent[tmp] < 0x20 && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
3311 textEncodingType = AV_ID3V2_UTF8;
3313 while (pExtContent[tmp] < 0x20 && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
3317 textEncodingType = AV_ID3V2_ISO_8859;
3320 #ifdef __MMFILE_TEST_MODE__
3321 debug_msg("tmp(%d) textEncodingType(%d), realCpyFrameNum(%d)\n", tmp, textEncodingType, realCpyFrameNum);
3324 if (textEncodingType == AV_ID3V2_UTF8) {
3325 pInfo->pUnsyncLyrics = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3327 if (pInfo->pUnsyncLyrics != NULL) {
3328 memset(pInfo->pUnsyncLyrics, 0, (realCpyFrameNum + 2));
3329 memcpy(pInfo->pUnsyncLyrics, pExtContent + tmp, realCpyFrameNum);
3330 pInfo->pUnsyncLyrics[realCpyFrameNum] = '\0';
3331 /*string copy with '\0'*/
3332 pInfo->unsynclyricsLen = realCpyFrameNum;
3333 _STRNCPY_EX(pInfo->pUnsyncLyrics, pExtContent, pInfo->unsynclyricsLen);
3335 debug_error("out of memoryu for SyncLyrics\n");
3338 pInfo->pUnsyncLyrics = mmfile_string_convert((const char *)&pExtContent[tmp], realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->unsynclyricsLen);
3341 #ifdef __MMFILE_TEST_MODE__
3342 debug_msg("Description info too small to parse realCpyFrameNum(%d)\n", realCpyFrameNum);
3348 #ifdef __MMFILE_TEST_MODE__
3349 debug_msg("pInfo->pUnsyncLyrics returned = (%s), pInfo->unsynclyricsLen(%d)\n", pInfo->pUnsyncLyrics, pInfo->unsynclyricsLen);
3351 pInfo->tagV2Info.bDescriptionMarked = true;
3352 } else if (strncmp((char *)CompTmp, "TCON", 4) == 0 && pInfo->tagV2Info.bGenreMarked == false) {
3353 if (textEncodingType == AV_ID3V2_UTF8) {
3354 pInfo->pGenre = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3355 if (pInfo->pGenre) {
3356 memcpy(pInfo->pGenre, pExtContent, realCpyFrameNum);
3357 pInfo->pGenre[realCpyFrameNum] = '\0';
3358 /*string copy with '\0'*/
3359 pInfo->genreLen = realCpyFrameNum;
3360 _STRNCPY_EX(pInfo->pGenre, pExtContent, pInfo->genreLen);
3363 pInfo->pGenre = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->genreLen);
3366 #ifdef __MMFILE_TEST_MODE__
3367 debug_msg("pInfo->pGenre returned = (%s), pInfo->genreLen(%d)\n", pInfo->pGenre, pInfo->genreLen);
3370 if ((pInfo->pGenre != NULL) && (pInfo->genreLen > 0)) {
3374 ret = is_numeric(pInfo->pGenre, pInfo->genreLen);
3377 sscanf(pInfo->pGenre, "%d", &int_genre);
3378 #ifdef __MMFILE_TEST_MODE__
3379 debug_msg("genre information is inteager [%d]\n", int_genre);
3382 /*Change int to string */
3383 if ((0 <= int_genre) && (int_genre < GENRE_COUNT - 1)) {
3384 /*save genreinfo like "(123)". mm_file_id3tag_restore_content_info convert it to string*/
3385 char tmp_genre[6] = {0, }; /*ex. "(123)+NULL"*/
3386 int tmp_genre_len = 0;
3388 memset(tmp_genre, 0, 6);
3389 snprintf(tmp_genre, sizeof(tmp_genre), "(%d)", int_genre);
3391 tmp_genre_len = strlen(tmp_genre);
3392 if (tmp_genre_len > 0) {
3393 if (pInfo->pGenre) _FREE_EX(pInfo->pGenre);
3394 pInfo->pGenre = mmfile_malloc(sizeof(char) * (tmp_genre_len + 1));
3395 if (pInfo->pGenre) {
3396 strncpy(pInfo->pGenre, tmp_genre, tmp_genre_len);
3397 pInfo->pGenre[tmp_genre_len] = 0;
3404 pInfo->tagV2Info.bGenreMarked = true;
3405 } else if (strncmp((char *)CompTmp, "TRCK", 4) == 0 && pInfo->tagV2Info.bTrackNumMarked == false) {
3406 if (textEncodingType == AV_ID3V2_UTF8) {
3407 pInfo->pTrackNum = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3408 if (pInfo->pTrackNum != NULL) {
3409 memcpy(pInfo->pTrackNum, pExtContent, realCpyFrameNum);
3410 pInfo->pTrackNum[realCpyFrameNum] = '\0';
3411 /*string copy with '\0'*/
3412 pInfo->tracknumLen = realCpyFrameNum;
3413 _STRNCPY_EX(pInfo->pTrackNum, pExtContent, pInfo->tracknumLen);
3416 pInfo->pTrackNum = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->tracknumLen);
3420 #ifdef __MMFILE_TEST_MODE__
3421 debug_msg("pInfo->pTrackNum returned = (%s), pInfo->tracknumLen(%d)\n", pInfo->pTrackNum, pInfo->tracknumLen);
3423 pInfo->tagV2Info.bTrackNumMarked = true;
3424 } else if (strncmp((char *)CompTmp, "TENC", 4) == 0 && pInfo->tagV2Info.bEncByMarked == false) {
3425 if (textEncodingType == AV_ID3V2_UTF8) {
3426 pInfo->pEncBy = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3427 if (pInfo->pEncBy != NULL) {
3428 memcpy(pInfo->pEncBy, pExtContent, realCpyFrameNum);
3429 pInfo->pEncBy[realCpyFrameNum] = '\0';
3430 /*string copy with '\0'*/
3431 pInfo->encbyLen = realCpyFrameNum;
3432 _STRNCPY_EX(pInfo->pEncBy, pExtContent, pInfo->encbyLen);
3435 pInfo->pEncBy = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->encbyLen);
3438 #ifdef __MMFILE_TEST_MODE__
3439 debug_msg("pInfo->pEncBy returned = (%s), pInfo->encbyLen(%d)\n", pInfo->pEncBy, pInfo->encbyLen);
3441 pInfo->tagV2Info.bEncByMarked = true;
3442 } else if (strncmp((char *)CompTmp, "WXXX", 4) == 0 && pInfo->tagV2Info.bURLMarked == false) {
3443 if (textEncodingType == AV_ID3V2_UTF8) {
3444 pInfo->pURL = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3445 if (pInfo->pURL != NULL) {
3446 memcpy(pInfo->pURL, pExtContent, realCpyFrameNum);
3447 pInfo->pURL[realCpyFrameNum] = '\0';
3448 /*string copy with '\0'*/
3449 pInfo->urlLen = realCpyFrameNum;
3450 _STRNCPY_EX(pInfo->pURL, pExtContent, pInfo->urlLen);
3453 pInfo->pURL = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->urlLen);
3456 #ifdef __MMFILE_TEST_MODE__
3457 debug_msg("pInfo->pURL returned = (%s), pInfo->urlLen(%d)\n", pInfo->pURL, pInfo->urlLen);
3459 pInfo->tagV2Info.bURLMarked = true;
3460 } else if (strncmp((char *)CompTmp, "TCOP", 4) == 0 && pInfo->tagV2Info.bCopyRightMarked == false) {
3461 if (textEncodingType == AV_ID3V2_UTF8) {
3462 pInfo->pCopyright = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3463 if (pInfo->pCopyright != NULL) {
3464 memcpy(pInfo->pCopyright, pExtContent, realCpyFrameNum);
3465 pInfo->pCopyright[realCpyFrameNum] = '\0';
3466 /*string copy with '\0'*/
3467 pInfo->copyrightLen = realCpyFrameNum;
3468 _STRNCPY_EX(pInfo->pCopyright, pExtContent, pInfo->copyrightLen);
3471 pInfo->pCopyright = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->copyrightLen);
3474 #ifdef __MMFILE_TEST_MODE__
3475 debug_msg("pInfo->pCopyright returned = (%s), pInfo->copyrightLen(%d)\n", pInfo->pCopyright, pInfo->copyrightLen);
3477 pInfo->tagV2Info.bCopyRightMarked = true;
3478 } else if (strncmp((char *)CompTmp, "TOPE", 4) == 0 && pInfo->tagV2Info.bOriginArtistMarked == false) {
3479 if (textEncodingType == AV_ID3V2_UTF8) {
3480 pInfo->pOriginArtist = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3481 if (pInfo->pOriginArtist != NULL) {
3482 memcpy(pInfo->pOriginArtist, pExtContent, realCpyFrameNum);
3483 pInfo->pOriginArtist[realCpyFrameNum] = '\0';
3484 /*string copy with '\0'*/
3485 pInfo->originartistLen = realCpyFrameNum;
3486 _STRNCPY_EX(pInfo->pOriginArtist, pExtContent, pInfo->originartistLen);
3489 pInfo->pOriginArtist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->originartistLen);
3492 #ifdef __MMFILE_TEST_MODE__
3493 debug_msg("pInfo->pOriginArtist returned = (%s), pInfo->originartistLen(%d)\n", pInfo->pOriginArtist, pInfo->originartistLen);
3495 pInfo->tagV2Info.bOriginArtistMarked = true;
3496 } else if (strncmp((char *)CompTmp, "TCOM", 4) == 0 && pInfo->tagV2Info.bComposerMarked == false) {
3497 if (textEncodingType == AV_ID3V2_UTF8) {
3498 pInfo->pComposer = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3499 if (pInfo->pComposer != NULL) {
3500 memcpy(pInfo->pComposer, pExtContent, realCpyFrameNum);
3501 pInfo->pComposer[realCpyFrameNum] = '\0';
3502 /*string copy with '\0'*/
3503 pInfo->composerLen = realCpyFrameNum;
3504 _STRNCPY_EX(pInfo->pComposer, pExtContent, pInfo->composerLen);
3507 pInfo->pComposer = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->composerLen);
3510 #ifdef __MMFILE_TEST_MODE__
3511 debug_msg("pInfo->pComposer returned = (%s), pInfo->originartistLen(%d)\n", pInfo->pComposer, pInfo->composerLen);
3513 pInfo->tagV2Info.bComposerMarked = true;
3514 } else if (strncmp((char *)CompTmp, "TDRC", 4) == 0 && pInfo->tagV2Info.bRecDateMarked == false) { /*TYER(year) and TRDA are replaced by the TDRC */
3515 if (textEncodingType == AV_ID3V2_UTF8) {
3516 pInfo->pRecDate = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3517 if (pInfo->pRecDate != NULL) {
3518 memcpy(pInfo->pRecDate, pExtContent, realCpyFrameNum);
3519 pInfo->pRecDate[realCpyFrameNum] = '\0';
3520 /*string copy with '\0'*/
3521 pInfo->recdateLen = realCpyFrameNum;
3522 _STRNCPY_EX(pInfo->pRecDate, pExtContent, pInfo->recdateLen);
3525 pInfo->pRecDate = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->recdateLen);
3528 #ifdef __MMFILE_TEST_MODE__
3529 debug_msg("pInfo->pRecDate returned = (%s), pInfo->recdateLen(%d)\n", pInfo->pRecDate, pInfo->recdateLen);
3531 pInfo->tagV2Info.bRecDateMarked = true;
3532 } else if (strncmp((char *)CompTmp, "TIT1", 4) == 0 && pInfo->tagV2Info.bContentGroupMarked == false) {
3533 if (textEncodingType == AV_ID3V2_UTF8) {
3534 pInfo->pContentGroup = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3535 if (pInfo->pContentGroup != NULL) {
3536 memcpy(pInfo->pContentGroup, pExtContent, realCpyFrameNum);
3537 pInfo->pContentGroup[realCpyFrameNum] = '\0';
3538 /*string copy with '\0'*/
3539 pInfo->contentGroupLen = realCpyFrameNum;
3540 _STRNCPY_EX(pInfo->pContentGroup, pExtContent, pInfo->contentGroupLen);
3543 pInfo->pContentGroup = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->contentGroupLen);
3545 #ifdef __MMFILE_TEST_MODE__
3546 debug_msg("pInfo->pContentGroup returned = (%s), pInfo->contentGroupLen(%d)\n", pInfo->pContentGroup, pInfo->contentGroupLen);
3548 pInfo->tagV2Info.bContentGroupMarked = true;
3549 } else if (strncmp((char *)CompTmp, "APIC", 4) == 0 && pInfo->tagV2Info.bImageMarked == false && realCpyFrameNum <= 2000000) {
3550 if (pExtContent[0] != '\0') {
3551 for (inx = 0; inx < MP3_ID3_IMAGE_MIME_TYPE_MAX_LENGTH - 1; inx++)
3552 pInfo->imageInfo.imageMIMEType[inx] = '\0';/*ini mimetype variable */
3554 while ((checkImgMimeTypeMax < MP3_ID3_IMAGE_MIME_TYPE_MAX_LENGTH - 1) && pExtContent[checkImgMimeTypeMax] != '\0') {
3555 pInfo->imageInfo.imageMIMEType[checkImgMimeTypeMax] = pExtContent[checkImgMimeTypeMax];
3556 checkImgMimeTypeMax++;
3558 pInfo->imageInfo.imgMimetypeLen = checkImgMimeTypeMax;
3560 pInfo->imageInfo.imgMimetypeLen = 0;
3563 imgstartOffset += checkImgMimeTypeMax;
3565 if (strncmp(pInfo->imageInfo.imageMIMEType, MIME_PRFIX, strlen(MIME_PRFIX)) != 0) {
3566 pInfo->imageInfo.imgMimetypeLen = 0;
3567 debug_error("APIC NOT VALID");
3571 if ((pExtContent[imgstartOffset] == '\0') && (realCpyFrameNum - imgstartOffset > 0)) {
3572 imgstartOffset++;/*endofMIME(1byte) */
3574 if (pExtContent[imgstartOffset] < AV_ID3V2_PICTURE_TYPE_MAX) {
3575 pInfo->imageInfo.pictureType = pExtContent[imgstartOffset];
3577 imgstartOffset++;/*PictureType(1byte) */
3579 if (pExtContent[imgstartOffset] != 0x0) {
3582 int new_dis_len = 0;
3583 char *tmp_desc = NULL;
3586 if (pExtContent[imgstartOffset + cur_pos] == '\0') {
3587 if (realCpyFrameNum < imgstartOffset + cur_pos) {
3588 debug_error("End of APIC Tag %d %d %d\n", realCpyFrameNum, imgstartOffset, cur_pos);
3591 /*check end of image description*/
3592 if ((pExtContent[imgstartOffset + cur_pos + 1] == gTagJPEGHeader[0]) ||
3593 (pExtContent[imgstartOffset + cur_pos + 1] == gTagPNGHeader[0])) {
3594 #ifdef __MMFILE_TEST_MODE__
3595 debug_msg("length of description (%d)", cur_pos);
3604 dis_len = cur_pos + 1;
3606 tmp_desc = mmfile_malloc(sizeof(char) * dis_len);
3608 if (tmp_desc != NULL) {
3609 memcpy(tmp_desc, pExtContent + imgstartOffset, dis_len);
3610 debug_msg("tmp_desc %s\n", tmp_desc);
3612 /*convert description*/
3613 pInfo->imageInfo.imageDescription = mmfile_string_convert(tmp_desc, dis_len, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&new_dis_len);
3614 debug_msg("new_desc %s(%d)\n", pInfo->imageInfo.imageDescription, new_dis_len);
3615 mmfile_free(tmp_desc);
3617 pInfo->imageInfo.imgDesLen = new_dis_len; /**/
3620 imgstartOffset += cur_pos;
3622 pInfo->imageInfo.imgDesLen = 0;
3625 if ((pExtContent[imgstartOffset] == '\0') && (realCpyFrameNum - imgstartOffset > 0)) {
3626 imgstartOffset++; /* endofDesceriptionType(1byte) */
3628 while (pExtContent[imgstartOffset] == '\0') { /*some content has useless '\0' in front of picture data */
3632 #ifdef __MMFILE_TEST_MODE__
3633 debug_msg("after scaning imgDescription imgstartOffset(%d) value!\n", imgstartOffset);
3636 if (realCpyFrameNum - imgstartOffset > 0) {
3637 pInfo->imageInfo.imageLen = realCpyFrameNum - imgstartOffset;
3638 pInfo->imageInfo.pImageBuf = mmfile_malloc(pInfo->imageInfo.imageLen + 1);
3640 if (pInfo->imageInfo.pImageBuf != NULL) {
3641 memcpy(pInfo->imageInfo.pImageBuf, pExtContent + imgstartOffset, pInfo->imageInfo.imageLen);
3642 pInfo->imageInfo.pImageBuf[pInfo->imageInfo.imageLen] = 0;
3645 if (IS_INCLUDE_URL(pInfo->imageInfo.imageMIMEType))
3646 pInfo->imageInfo.bURLInfo = true; /*if mimetype is "-->", image date has an URL */
3648 #ifdef __MMFILE_TEST_MODE__
3649 debug_msg("No APIC image!! realCpyFrameNum(%d) - imgstartOffset(%d)\n", realCpyFrameNum, imgstartOffset);
3655 checkImgMimeTypeMax = 0;
3658 pInfo->tagV2Info.bImageMarked = true;
3660 #ifdef __MMFILE_TEST_MODE__
3661 debug_msg("CompTmp(%s) This Frame ID currently not Supports!!\n", CompTmp);
3667 #ifdef __MMFILE_TEST_MODE__
3668 debug_msg("mmf_file_id3tag_parse_v224: All of the pExtContent Values are NULL\n");
3673 curPos += purelyFramelen;
3674 if (purelyFramelen != 0)
3675 needToloopv2taglen = MP3_TAGv2_23_TXT_HEADER_LEN;
3678 if (pExtContent) _FREE_EX(pExtContent);
3679 memset(CompTmp, 0, 4);
3680 if (curPos < taglen) {
3681 needToloopv2taglen -= oneFrameLen;
3684 needToloopv2taglen = MP3_TAGv2_23_TXT_HEADER_LEN;
3688 realCpyFrameNum = 0;
3689 textEncodingType = 0;
3695 release_characterset_array(charset_array);
3705 void mm_file_id3tag_restore_content_info(AvFileContentInfo *pInfo)
3707 char *mpegAudioGenre = NULL/*, *tmpGenreForV1Tag = NULL*/;
3708 bool bAdditionGenre = false /*, bMpegAudioFrame = false*/;
3709 int mpegAudioFileLen = 0, idv2IntGenre = 148/*, tmpinx = 0, tmpinx2=0*/;
3711 char *pGenreForUTF16;
3713 unsigned char genre = pInfo->genre;
3715 /* for Genre Info */
3716 if (pInfo->tagV2Info.bGenreMarked == false) {
3717 if (pInfo->bV1tagFound == true) {
3718 #ifdef __MMFILE_TEST_MODE__
3719 debug_msg("Genre: %d\n", genre);
3724 if (MpegAudio_Genre[genre] != NULL) {
3725 pInfo->genreLen = strlen(MpegAudio_Genre[genre]);
3726 if (pInfo->genreLen > 0) {
3727 /* Give space for NULL character. Hence added "+1" */
3728 pInfo->pGenre = mmfile_malloc(sizeof(char) * (pInfo->genreLen + 1));
3729 if (pInfo->pGenre) {
3730 strncpy(pInfo->pGenre, MpegAudio_Genre[genre], pInfo->genreLen);
3731 pInfo->pGenre[pInfo->genreLen] = '\0';
3736 #ifdef __MMFILE_TEST_MODE__
3737 debug_msg("Genre was not Found.\n");
3740 } else if (pInfo->tagV2Info.bGenreMarked == true) {
3741 if (pInfo->genreLen && pInfo->tagV2Info.bGenreUTF16) {
3742 pInfo->pGenre[pInfo->genreLen + 1] = '\0';
3743 mpegAudioGenre = mmfile_malloc(sizeof(char) * (pInfo->genreLen * AV_WM_LOCALCODE_SIZE_MAX + 1));
3745 pGenreForUTF16 = (char *)pInfo->pGenre;
3747 if (WmConvert2LCode(mpegAudioGenre, sizeof(char) * AV_WM_LOCALCODE_SIZE_MAX * (pInfo->genreLen + 1), pGenreForUTF16)) {
3748 pInfo->genreLen = strlen(mpegAudioGenre);
3749 mpegAudioGenre[pInfo->genreLen] = '\0';
3753 #ifdef __MMFILE_TEST_MODE__
3754 debug_msg("pInfo->genreLen size is Zero Or not UTF16 code! genreLen[%d] genre[%s]\n", pInfo->genreLen, pInfo->pGenre);
3756 if (pInfo->pGenre) {
3757 pInfo->genreLen = strlen(pInfo->pGenre);
3758 mpegAudioGenre = mmfile_malloc(sizeof(char) * (pInfo->genreLen + 1));
3759 if (mpegAudioGenre != NULL) {
3760 mpegAudioGenre[pInfo->genreLen] = '\0';
3761 strncpy(mpegAudioGenre, pInfo->pGenre, pInfo->genreLen);
3764 pInfo->genreLen = 0;
3768 if (pInfo->pGenre) _FREE_EX(pInfo->pGenre);
3771 if (mpegAudioGenre != NULL) {
3774 * (XXX) XXX is 0 - 148
3776 pInfo->genreLen = strlen(mpegAudioGenre);
3777 if (pInfo->genreLen >= 3 &&
3778 mpegAudioGenre[0] == '(' && mpegAudioGenre[pInfo->genreLen - 1] == ')') {
3779 bAdditionGenre = true;
3780 for (mpegAudioFileLen = 1; mpegAudioFileLen <= pInfo->genreLen - 2; mpegAudioFileLen++) {
3781 if (mpegAudioGenre[mpegAudioFileLen] < '0' || mpegAudioGenre[mpegAudioFileLen] > '9') {
3782 bAdditionGenre = false;
3788 if (bAdditionGenre == true) {
3789 idv2IntGenre = atoi(mpegAudioGenre + 1);
3791 if (idv2IntGenre > 147 || idv2IntGenre < 0)
3794 if (MpegAudio_Genre[idv2IntGenre] != NULL) {
3795 pInfo->genreLen = strlen(MpegAudio_Genre[idv2IntGenre]);
3796 if (pInfo->genreLen > 0) {
3797 /* Give space for NULL character. Hence added "+1" */
3798 pInfo->pGenre = mmfile_malloc(sizeof(char) * (pInfo->genreLen + 1));
3799 if (pInfo->pGenre) {
3800 strncpy(pInfo->pGenre, MpegAudio_Genre[idv2IntGenre], pInfo->genreLen);
3801 pInfo->pGenre[pInfo->genreLen] = 0;
3805 #ifdef __MMFILE_TEST_MODE__
3806 debug_msg("pInfo->pGenre = %s\n", pInfo->pGenre);
3808 } else if (bAdditionGenre == false && pInfo->genreLen > 0) {
3813 /* Give space for NULL character. Hence added "+1" */
3814 pInfo->pGenre = mmfile_malloc(sizeof(char) * (pInfo->genreLen + 1));
3815 if (pInfo->pGenre) {
3816 strncpy(pInfo->pGenre, mpegAudioGenre, pInfo->genreLen);
3817 pInfo->pGenre[pInfo->genreLen] = '\0';
3819 #ifdef __MMFILE_TEST_MODE__
3820 debug_msg("pInfo->pGenre = %s, pInfo->genreLen = %d\n", pInfo->pGenre, pInfo->genreLen);
3823 #ifdef __MMFILE_TEST_MODE__
3824 debug_msg("Failed to \"(...)\" value to genre = %s\n", pInfo->pGenre);
3828 #ifdef __MMFILE_TEST_MODE__
3829 debug_msg("mpegAudioGenre = %x\n", mpegAudioGenre);
3833 _FREE_EX(mpegAudioGenre);
3836 #ifdef __MMFILE_TEST_MODE__
3837 debug_msg("Neither ID3 v1 nor v2 info doesn't have Genre Info.\n");
3843 void mm_file_free_synclyrics_list(GList *synclyrics_list)
3847 AvSynclyricsInfo *synclyrics_info = NULL;
3849 if (synclyrics_list == NULL) {
3853 list_len = g_list_length(synclyrics_list);
3854 for (idx = 0; idx < list_len; idx++) {
3855 synclyrics_info = g_list_nth_data(synclyrics_list, idx);
3857 if (synclyrics_info != NULL) {
3858 mmfile_free(synclyrics_info->lyric_info);
3859 mmfile_free(synclyrics_info);
3863 if (synclyrics_list != NULL) {
3864 g_list_free(synclyrics_list);
3865 synclyrics_list = NULL;