modify build option and update code by Tizen coding convention.
[platform/core/multimedia/libmm-fileinfo.git] / utils / mm_file_util_tag.c
1 /*
2  * libmm-fileinfo
3  *
4  * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: Haejeong Kim <backto.kim@samsung.com>
7  *
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
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
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.
19  *
20  */
21
22 #include <stdio.h>
23 #include <string.h>
24 #include <stdlib.h>
25 #include <ctype.h>
26 #include <vconf.h>
27 #include <glib.h>
28
29 #include "mm_file_debug.h"
30 #include "mm_file_utils.h"
31
32 #define ENABLE_ITUNES_META              /*All itunes metadata extracted by ffmpeg. see mov_read_udta_string() but Some cover art not support. */
33
34 typedef struct _mmfilemp4basicboxheader {
35         unsigned int size;
36         unsigned int type;
37         long long start_offset; /*huge file*/
38 } MMFILE_MP4_BASIC_BOX_HEADER;
39
40 typedef struct _mmfilemp4ftpybox {
41         unsigned int major_brand;
42         unsigned short major_version;
43         unsigned short minor_version;
44         unsigned int *compatiable_brands;
45 } MMFILE_MP4_FTYPBOX;
46
47 typedef enum {
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;
55
56 typedef struct _mmfile3gptagtextbox {
57         unsigned char version;
58         unsigned char flag[3];
59         unsigned char language[2];
60         unsigned char *text;
61 } MMFILE_3GP_TEXT_TAGBOX;
62
63 typedef struct _mmfile3gptagyearbox {
64         unsigned char version;
65         unsigned char flag[3];
66         unsigned short year;
67 } MMFILE_3GP_YEAR_TAGBOX;
68
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;
76
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;
85
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;
94
95 typedef struct _mmfile3gphdlrbox {
96         unsigned int  version;
97         unsigned int  pre_defined;
98         unsigned int  handler_type;
99         unsigned int  reserved[3];
100         unsigned char *boxname;
101 } MMFILE_3GP_HANDLER_BOX;
102
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;
109
110 typedef struct _mmfilelocibox {
111         unsigned char version;
112         unsigned char flag[3];
113         unsigned char language[2];
114         unsigned char *name;
115         unsigned char role;
116         float         longitude;
117         float         latitude;
118         float         altitude;
119         unsigned char *astronomical_body;
120         unsigned char *additional_notes;
121 } MMFILE_3GP_LOCATION_TAGBOX;
122
123 typedef struct _mmfilesmtabox {
124         unsigned int tmp;
125         unsigned int length;
126         unsigned char saut[4];
127         unsigned int value;
128 } MMFILE_M4A_SMTA_TAGBOX;
129
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
144
145
146 #define FOURCC(a, b, c, d) ((a) + ((b) << 8) + ((c) << 16) + ((d) << 24))
147
148 /*#define       MIN(a, b) (((a) < (b)) ? (a):(b))*/
149
150 #define GENRE_COUNT     149
151
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"
167                                                   };
168
169
170 static int GetStringFromTextTagBox(MMFileFormatContext *formatContext, MMFileIOHandle *fp, MMFILE_MP4_BASIC_BOX_HEADER *basic_header, eMMFILE_3GP_TEXT_TAG eTag)
171 {
172         int ret = MMFILE_UTIL_FAIL;    /*fail*/
173         MMFILE_3GP_TEXT_TAGBOX texttag = {0, };
174         int readed = 0;
175         int textBytes = 0;
176         char *temp_text = NULL;
177
178         if (!formatContext || !fp || !basic_header) {
179                 debug_error("invalid param\n");
180                 return MMFILE_UTIL_FAIL;
181         }
182
183         textBytes = basic_header->size - MMFILE_MP4_BASIC_BOX_HEADER_LEN - MMFILE_3GP_TEXT_TAGBOX_LEN;
184
185         readed = mmfile_read(fp, (unsigned char *)&texttag, MMFILE_3GP_TEXT_TAGBOX_LEN);
186         if (readed != MMFILE_3GP_TEXT_TAGBOX_LEN) {
187                 debug_error("read text tag header fail\n");
188                 ret = MMFILE_UTIL_FAIL;
189                 goto exception;
190         }
191
192         if (textBytes <= 1) { /* there exist only 00(null) */
193                 debug_error("Text is NULL\n");
194                 goto exception;
195         }
196
197         texttag.text = mmfile_malloc(textBytes);
198         if (!texttag.text) {
199                 debug_error("malloc fail for text box\n");
200                 ret = MMFILE_UTIL_FAIL;
201                 goto exception;
202         }
203
204         readed = mmfile_read(fp, (unsigned char *)texttag.text, textBytes);
205         if (readed != textBytes) {
206                 debug_error("read text fail\n");
207                 ret = MMFILE_UTIL_FAIL;
208                 goto exception;
209         }
210
211         /* check BOM char */
212         if ((texttag.text[0] == 0xFE) && (texttag.text[1] == 0xFF)) {
213                 /* this char is UTF-16 */
214                 unsigned int bytes_written = 0;
215                 temp_text = mmfile_string_convert((const char *)&texttag.text[2], readed - 2, "UTF-8", "UTF-16", NULL, (unsigned int *)&bytes_written);
216         } else {
217                 temp_text = mmfile_strdup((const char *)texttag.text);
218         }
219
220         switch (eTag) {
221                 case eMMFILE_3GP_TAG_TITLE: {
222                                 if (!formatContext->title) {
223                                         formatContext->title = temp_text;
224                                 }
225                                 break;
226                         }
227                 case eMMFILE_3GP_TAG_CAPTION: {
228                                 if (!formatContext->description) {
229                                         formatContext->description = temp_text;
230                                 }
231                                 break;
232                         }
233                 case eMMFILE_3GP_TAG_COPYRIGHT: {
234                                 if (!formatContext->copyright) {
235                                         formatContext->copyright = temp_text;
236                                 }
237                                 break;
238                         }
239                 case eMMFILE_3GP_TAG_PERFORMER: {
240                                 if (!formatContext->artist) {
241                                         formatContext->artist = temp_text;
242                                 }
243                                 break;
244                         }
245                 case eMMFILE_3GP_TAG_AUTHOR: {
246                                 if (!formatContext->author) {
247                                         formatContext->author = temp_text;
248                                 }
249                                 break;
250                         }
251                 case eMMFILE_3GP_TAG_GENRE: {
252                                 if (!formatContext->genre) {
253                                         formatContext->genre = temp_text;
254                                 }
255                                 break;
256                         }
257                 default: {
258                                 debug_warning("Not supported Text Tag type[%d]\n", eTag);
259                                 break;
260                         }
261         }
262
263         mmfile_free(texttag.text);
264         texttag.text = NULL;
265         mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
266
267         return MMFILE_UTIL_SUCCESS;
268
269 exception:
270         mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
271         if (texttag.text) {
272                 mmfile_free(texttag.text);
273         }
274         return ret;
275 }
276
277 static int GetYearFromYearTagBox(MMFileFormatContext *formatContext, MMFileIOHandle *fp, MMFILE_MP4_BASIC_BOX_HEADER *basic_header)
278 {
279 #define MAX_YEAR_BUFFER 10
280         int readed = 0;
281         MMFILE_3GP_YEAR_TAGBOX yearbox = {0, };
282         char temp_year[MAX_YEAR_BUFFER] = {0, };
283
284         if (!formatContext || !fp || !basic_header) {
285                 debug_error("invalid param\n");
286                 return MMFILE_UTIL_FAIL;
287         }
288
289         readed = mmfile_read(fp, (unsigned char *)&yearbox, MMFILE_3GP_YEAR_TAGBOX_LEN);
290         if (readed != MMFILE_3GP_YEAR_TAGBOX_LEN) {
291                 debug_error("read yeartag header fail\n");
292                 goto exception;
293         }
294
295         if (!formatContext->year) {
296                 yearbox.year = mmfile_io_be_int16(yearbox.year);
297                 snprintf(temp_year, MAX_YEAR_BUFFER, "%d", yearbox.year);
298                 temp_year[MAX_YEAR_BUFFER - 1] = '\0';
299                 formatContext->year = mmfile_strdup((const char *)temp_year);
300         }
301
302         mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
303         return MMFILE_UTIL_SUCCESS;
304
305 exception:
306         mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
307
308         return MMFILE_UTIL_FAIL;
309 }
310
311 static int GetAlbumFromAlbumTagBox(MMFileFormatContext *formatContext, MMFileIOHandle *fp, MMFILE_MP4_BASIC_BOX_HEADER *basic_header)
312 {
313         int albumTitleLen = 0;
314         char *temp_text = NULL;
315         int readed = 0;
316         int trackFlags = 0;
317         MMFILE_3GP_ALBUM_TAGBOX albumbox = {0, };
318
319         if (!formatContext || !fp || !basic_header) {
320                 debug_error("invalid param\n");
321                 return MMFILE_UTIL_FAIL;
322         }
323
324         readed = mmfile_read(fp, (unsigned char *)&albumbox, MMFILE_3GP_ALBUM_TAGBOX_LEN);
325         if (readed != MMFILE_3GP_ALBUM_TAGBOX_LEN) {
326                 debug_error("read albumtag header fail\n");
327                 goto exception;
328         }
329
330         albumTitleLen = basic_header->size - MMFILE_MP4_BASIC_BOX_HEADER_LEN - MMFILE_3GP_ALBUM_TAGBOX_LEN - 1; /* 1: track number */
331         if (albumTitleLen > 1) { /* there exist only 00(null) */
332 #ifdef __MMFILE_TEST_MODE__
333                 debug_msg("albumTitleLen=%d\n", albumTitleLen);
334 #endif
335
336                 albumbox.albumtile = mmfile_malloc(albumTitleLen + 1);  /* 1: for null char */
337                 if (!albumbox.albumtile) {
338                         debug_error("malloc fail for album title text\n");
339                         goto exception;
340                 }
341
342                 readed = mmfile_read(fp, (unsigned char *)albumbox.albumtile, albumTitleLen);
343                 if (readed != albumTitleLen) {
344                         debug_error("read album title fail\n");
345                         goto exception;
346                 }
347
348                 if (albumbox.albumtile[albumTitleLen - 1] == '\0') { /* there exist track number */
349                         trackFlags = 1;
350                 } else {
351                         trackFlags = 0;
352                         readed = mmfile_read(fp, (unsigned char *)&(albumbox.albumtile[albumTitleLen]), 1);
353                         if (readed != 1) {
354                                 debug_error("read album title fail\n");
355                                 goto exception;
356                         }
357                         albumbox.albumtile[albumTitleLen] = '\0';
358                 }
359
360                 /* check BOM char */
361                 if ((albumbox.albumtile[0] == 0xFE) && (albumbox.albumtile[1] == 0xFF)) {
362                         /* this char is UTF-16 */
363                         unsigned int bytes_written = 0;
364                         temp_text = mmfile_string_convert((const char *)&albumbox.albumtile[2], readed - 2, "UTF-8", "UTF-16", NULL, (unsigned int *)&bytes_written);
365                 } else {
366                         temp_text = mmfile_strdup((const char *)albumbox.albumtile);
367                 }
368
369                 if (!formatContext->album) {
370                         formatContext->album = temp_text;
371                 }
372
373 #ifdef __MMFILE_TEST_MODE__
374                 debug_msg("formatContext->album=%s, strlen=%d\n", formatContext->album, strlen(formatContext->album));
375 #endif
376         }
377
378         if (trackFlags) {
379                 readed = mmfile_read(fp, (unsigned char *)&albumbox.trackNumber, 1);
380                 if (readed != 1) {
381                         debug_error("read track number fail\n");
382                         goto exception;
383                 }
384
385                 if (formatContext->tagTrackNum == 0) {
386                         char tracknum[10] = {0, };
387                         snprintf(tracknum, 10, "%d", albumbox.trackNumber);
388                         tracknum[9] = '\0';
389                         formatContext->tagTrackNum = mmfile_strdup((const char *)tracknum);
390                 }
391         }
392
393         mmfile_free(albumbox.albumtile);
394         mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
395
396         return MMFILE_UTIL_SUCCESS;
397
398 exception:
399         mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
400         mmfile_free(albumbox.albumtile);
401
402         return MMFILE_UTIL_FAIL;
403 }
404
405 static int GetRatingFromRatingTagBox(MMFileFormatContext *formatContext, MMFileIOHandle *fp, MMFILE_MP4_BASIC_BOX_HEADER *basic_header)
406 {
407         int readed = 0;
408         int  ratinginfoLen = 0;
409         char *temp_text = NULL;
410
411         MMFILE_3GP_RATING_TAGBOX ratingTag = {0, };
412
413         if (!formatContext || !fp || !basic_header) {
414                 debug_error("invalid param\n");
415                 return MMFILE_UTIL_FAIL;
416         }
417
418         readed = mmfile_read(fp, (unsigned char *)&ratingTag, MMFILE_3GP_RATING_TAGBOX_LEN);
419         if (readed != MMFILE_3GP_RATING_TAGBOX_LEN) {
420                 debug_error("read rating tag header fail\n");
421                 goto exception;
422         }
423
424         ratinginfoLen = basic_header->size - MMFILE_MP4_BASIC_BOX_HEADER_LEN - MMFILE_3GP_RATING_TAGBOX_LEN;
425
426         if (ratinginfoLen == 1) {
427                 debug_error("Rating Text is NULL\n");
428                 goto exception;
429         }
430
431         ratingTag.ratingInfo = mmfile_malloc(ratinginfoLen);
432         if (!ratingTag.ratingInfo) {
433                 debug_error("rating info error\n");
434                 goto exception;
435         }
436
437         readed = mmfile_read(fp, (unsigned char *)ratingTag.ratingInfo, ratinginfoLen);
438         if (readed != ratinginfoLen) {
439                 debug_error("read rating info string fail\n");
440                 goto exception;
441         }
442
443         /* check BOM char */
444         if ((ratingTag.ratingInfo[0] == 0xFE) && (ratingTag.ratingInfo[1] == 0xFF)) {
445                 /* this char is UTF-16 */
446                 unsigned int bytes_written = 0;
447                 temp_text = mmfile_string_convert((const char *)&ratingTag.ratingInfo[2], readed - 2, "UTF-8", "UTF-16", NULL, (unsigned int *)&bytes_written);
448         } else {
449                 temp_text = mmfile_strdup((const char *)ratingTag.ratingInfo);
450         }
451
452         if (!formatContext->rating) {
453                 formatContext->rating = temp_text;
454         } else {
455                 mmfile_free(temp_text);
456         }
457
458         mmfile_free(ratingTag.ratingInfo);
459         mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
460
461         return MMFILE_UTIL_SUCCESS;
462
463 exception:
464         mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
465         mmfile_free(ratingTag.ratingInfo);
466
467         return MMFILE_UTIL_FAIL;
468 }
469
470
471 static int GetClassficationFromClsfTagBox(MMFileFormatContext *formatContext, MMFileIOHandle *fp, MMFILE_MP4_BASIC_BOX_HEADER *basic_header)
472 {
473         int classinfoLen = 0;
474         int readed = 0;
475         char *temp_text = NULL;
476         MMFILE_3GP_CLASSIFICATION_TAGBOX classTag = {0, };
477
478         if (!formatContext || !fp || !basic_header) {
479                 debug_error("invalid param\n");
480                 return MMFILE_UTIL_FAIL;
481         }
482
483         readed = mmfile_read(fp, (unsigned char *)&classTag, MMFILE_3GP_CLASS_TAGBOX_LEN);
484         if (readed != MMFILE_3GP_CLASS_TAGBOX_LEN) {
485                 debug_error("read classification tag header fail\n");
486                 goto exception;
487         }
488
489
490         classinfoLen = basic_header->size - MMFILE_MP4_BASIC_BOX_HEADER_LEN - MMFILE_3GP_CLASS_TAGBOX_LEN;
491         if (classinfoLen == 1) {
492                 debug_error("Classification Text is NULL\n");
493                 goto exception;
494         }
495
496         classTag.classificationInfo = mmfile_malloc(classinfoLen);
497         if (!classTag.classificationInfo) {
498                 debug_error("class info error\n");
499                 goto exception;
500         }
501
502         readed = mmfile_read(fp, (unsigned char *)classTag.classificationInfo, classinfoLen);
503         if (readed != classinfoLen) {
504                 debug_error("read class info string fail\n");
505                 goto exception;
506         }
507
508         /* check BOM char */
509         if ((classTag.classificationInfo[0] == 0xFE) && (classTag.classificationInfo[1] == 0xFF)) {
510                 /* this char is UTF-16 */
511                 unsigned int bytes_written = 0;
512                 temp_text = mmfile_string_convert((const char *)&classTag.classificationInfo[2], readed - 2, "UTF-8", "UTF-16", NULL, (unsigned int *)&bytes_written);
513         } else {
514                 temp_text = mmfile_strdup((const char *)classTag.classificationInfo);
515         }
516
517         if (!formatContext->classification) {
518                 formatContext->classification = temp_text;
519         } else {
520                 mmfile_free(temp_text);
521         }
522
523         mmfile_free(classTag.classificationInfo);
524         mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
525
526         return MMFILE_UTIL_SUCCESS;
527
528 exception:
529         mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
530         mmfile_free(classTag.classificationInfo);
531
532         return MMFILE_UTIL_FAIL;
533 }
534
535 /**
536  * The Location Information box
537  * --------------------+-------------------+-----------------------------------+------
538  * Field                                Type                            Details                                                         Value
539  * --------------------+-------------------+-----------------------------------+------
540  * BoxHeader.Size               Unsigned int(32)
541  * BoxHeader.Type               Unsigned int(32)                                                                                'loci'
542  * BoxHeader.Version    Unsigned int(8)                                                                                 0
543  * BoxHeader.Flags              Bit(24)                                                                                                 0
544  * Pad                                  Bit(1)                                                                                                  0
545  * Language                             Unsigned int(5)[3]      Packed ISO-639-2/T language code
546  * Name                                 String                          Text of place name
547  * Role                                 Unsigned int(8)         Non-negative value indicating role
548  *                                                                                       of location
549  * Longitude                    Unsigned int(32)        Fixed-point value of the longitude
550  * Latitude                             Unsigned int(32)        Fixed-point value of the latitude
551  * Altitude                             Unsigned int(32)        Fixed-point value of the Altitude
552  * Astronomical_body    String                          Text of astronomical body
553  * Additional_notes             String                          Text of additional location-related
554  *                                                                                       information
555  * --------------------+-------------------+-----------------------------------+------
556  */
557 static int _get_char_position(unsigned char *src, char ch, int max)
558 {
559         int i;
560         for (i = 0; i < max; i++) {
561                 if (*(src + i) == ch)
562                         return i;
563         }
564
565         return -1;
566 }
567
568 static int GetLocationFromLociTagBox(MMFileFormatContext *formatContext, MMFileIOHandle *fp, MMFILE_MP4_BASIC_BOX_HEADER *basic_header)
569 {
570
571         MMFILE_3GP_LOCATION_TAGBOX lociTag = {0, };
572         int readed = 0;
573         int bufferLen = 0;
574         unsigned char *buffer = NULL;
575         unsigned char *p = NULL;
576         int pos = 0;
577         unsigned int bytes_written = 0;
578         unsigned int name_sz = 0;
579         unsigned int astro_sz = 0;
580
581         int ilong, ilati, ialti;
582         float flong, flati, falti;
583
584
585         if (!formatContext || !fp || !basic_header) {
586                 debug_error("invalid param\n");
587                 return MMFILE_UTIL_FAIL;
588         }
589
590         readed = mmfile_read(fp, (unsigned char *)&lociTag, 6);  /*6 = version + flag + pad + language */
591         if (readed != 6) {
592                 debug_error("read location tag header fail\n");
593                 goto exception;
594         }
595
596         /*buffer len = name + role + ... + additional notes length */
597         bufferLen = basic_header->size - MMFILE_MP4_BASIC_BOX_HEADER_LEN - 6;
598         if (bufferLen < 1) {
599                 debug_error("too small buffer\n");
600                 goto exception;
601         }
602
603         buffer = mmfile_malloc(bufferLen);
604         if (!buffer) {
605                 debug_error("buffer malloc error\n");
606                 goto exception;
607         }
608
609         readed = mmfile_read(fp, (unsigned char *)buffer, bufferLen);
610         if (readed != bufferLen) {
611                 debug_error("read location tag fail\n");
612                 goto exception;
613         }
614         p = buffer;
615
616         /*name*/
617         pos = _get_char_position(p, '\0', readed - (1 + 4 + 4 + 4 + 2));
618         if (pos >= 0) {
619                 if (p[0] == 0xFE && p[1] == 0xFF) {
620                         lociTag.name = (unsigned char *)mmfile_string_convert((const char *)(p + 2), pos - 2, "UTF-8", "UTF-16", NULL, (unsigned int *)&bytes_written);
621                 } else {
622                         lociTag.name = (unsigned char *)mmfile_strdup((const char *)p);
623                 }
624         } else {
625                 goto exception;
626         }
627         name_sz = pos + 1;
628         p += (pos + 1);
629
630         /*role*/
631         lociTag.role = *p;
632         p++;
633
634 #ifdef __MMFILE_TEST_MODE__
635         debug_msg("long: 0x%02X 0x%02X 0x%02X 0x%02X \n", *(p + 0), *(p + 1), *(p + 2), *(p + 3));
636         debug_msg("lati: 0x%02X 0x%02X 0x%02X 0x%02X \n", *(p + 4), *(p + 5), *(p + 6), *(p + 7));
637         debug_msg("alti: 0x%02X 0x%02X 0x%02X 0x%02X \n", *(p + 8), *(p + 9), *(p + 10), *(p + 11));
638 #endif
639
640         ilong = mmfile_io_be_uint32(*(unsigned int *)p);
641         ilati = mmfile_io_be_uint32(*(unsigned int *)(p + 4));
642         ialti = mmfile_io_be_uint32(*(unsigned int *)(p + 8));
643
644         flong = (float)ilong / (1 << 16);
645         flati = (float)ilati / (1 << 16);
646         falti = (float)ialti / (1 << 16);
647
648         /*longitude*/
649         lociTag.longitude = flong;
650         /*latitude*/
651         lociTag.latitude = flati;
652         /*altitude*/
653         lociTag.altitude = falti;
654
655         p += 12;
656
657         /*astronomical body*/
658         pos = _get_char_position(p, '\0', readed - (name_sz + 1 + 4 + 4 + 4 + 1));
659         if (pos >= 0) {
660                 if (p[0] == 0xFE && p[1] == 0xFF) {
661                         lociTag.astronomical_body = (unsigned char *)mmfile_string_convert((const char *)(p + 2), pos - 2, "UTF-8", "UTF-16", NULL, (unsigned int *)&bytes_written);
662                 } else {
663                         lociTag.astronomical_body = (unsigned char *)mmfile_strdup((const char *)p);
664                 }
665         } else {
666                 goto exception;
667         }
668         astro_sz = pos + 1;
669         p += (pos + 1);
670
671         /*additional notes*/
672         pos = _get_char_position(p, '\0', readed - (name_sz + 1 + 4 + 4 + 4 + astro_sz));
673         if (pos >= 0) {
674                 if (p[0] == 0xFE && p[1] == 0xFF) {
675                         lociTag.additional_notes = (unsigned char *)mmfile_string_convert((const char *)(p + 2), pos - 2, "UTF-8", "UTF-16", NULL, (unsigned int *)&bytes_written);
676                 } else {
677                         lociTag.additional_notes = (unsigned char *)mmfile_strdup((const char *)p);
678                 }
679         } else {
680                 goto exception;
681         }
682
683 #ifdef __MMFILE_TEST_MODE__
684         debug_msg("** Location Information **\n");
685         debug_msg("Name             : %s\n", lociTag.name);
686         debug_msg("Role             : %d (0: shooting, 1: real, 2: fictional, other: reserved)\n", lociTag.role);
687         debug_msg("Longitude        : %16.16f\n", lociTag.longitude);
688         debug_msg("Latitude         : %16.16f\n", lociTag.latitude);
689         debug_msg("Altitude         : %16.16f\n", lociTag.altitude);
690         debug_msg("Astronomical body: %s\n", lociTag.astronomical_body);
691         debug_msg("Additional notes : %s\n", lociTag.additional_notes);
692 #endif
693
694         formatContext->longitude = lociTag.longitude;
695         formatContext->latitude = lociTag.latitude;
696         formatContext->altitude = lociTag.altitude;
697
698         mmfile_free(buffer);
699         mmfile_free(lociTag.name);
700         mmfile_free(lociTag.astronomical_body);
701         mmfile_free(lociTag.additional_notes);
702
703         mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
704         return MMFILE_UTIL_SUCCESS;
705
706 exception:
707         mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
708         mmfile_free(buffer);
709         mmfile_free(lociTag.name);
710         mmfile_free(lociTag.astronomical_body);
711         mmfile_free(lociTag.additional_notes);
712
713         return MMFILE_UTIL_FAIL;
714 }
715
716 static int GetSAUTInfoFromSMTATagBox(MMFileFormatContext *formatContext, MMFileIOHandle *fp, MMFILE_MP4_BASIC_BOX_HEADER *basic_header)
717 {
718         MMFILE_M4A_SMTA_TAGBOX smtaTag = {0, };
719         int readed = 0;
720
721         if (!formatContext || !fp || !basic_header) {
722                 debug_error("invalid param\n");
723                 return MMFILE_UTIL_FAIL;
724         }
725
726         readed = mmfile_read(fp, (unsigned char *)&smtaTag, sizeof(MMFILE_M4A_SMTA_TAGBOX));
727         if (readed != sizeof(MMFILE_M4A_SMTA_TAGBOX)) {
728                 debug_error("read smta tag header fail\n");
729                 goto exception;
730         }
731
732         smtaTag.length = mmfile_io_be_uint32(smtaTag.length);
733         smtaTag.value = mmfile_io_be_uint32(smtaTag.value);
734 #ifdef __MMFILE_TEST_MODE__
735         debug_msg("Len : 0x%x", smtaTag.length);
736         debug_msg("Saut : 0x%x 0x%x 0x%x 0x%x", smtaTag.saut[0], smtaTag.saut[1], smtaTag.saut[2], smtaTag.saut[3]);
737         debug_msg("Value : 0x%x", smtaTag.value);
738 #endif
739
740         if (smtaTag.saut[0] == 's'
741             && smtaTag.saut[1] == 'a'
742             && smtaTag.saut[2] == 'u'
743             && smtaTag.saut[3] == 't') {
744                 if (smtaTag.value == 0x01) {
745 #ifdef __MMFILE_TEST_MODE__
746                         debug_msg("This has saut tag and valid value");
747 #endif
748                         formatContext->smta = 1;
749                 } else {
750                         debug_error("This has saut tag and but invalid value");
751                         goto exception;
752                 }
753         } else {
754                 debug_error("This hasn't saut tag and valid value");
755                 goto exception;
756         }
757
758         return MMFILE_UTIL_SUCCESS;
759
760 exception:
761         mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
762
763         return MMFILE_UTIL_FAIL;
764 }
765
766 static int GetValueFromCDISTagBox(MMFileFormatContext *formatContext, MMFileIOHandle *fp, MMFILE_MP4_BASIC_BOX_HEADER *basic_header)
767 {
768         unsigned int value = 0;
769         int readed = 0;
770
771         if (!formatContext || !fp || !basic_header) {
772                 debug_error("invalid param\n");
773                 return MMFILE_UTIL_FAIL;
774         }
775
776         readed = mmfile_read(fp, (unsigned char *)&value, sizeof(unsigned int));
777         if (readed != sizeof(unsigned int)) {
778                 debug_error("read cdis tag header fail\n");
779                 goto exception;
780         }
781
782         value = mmfile_io_be_uint32(value);
783
784 #ifdef __MMFILE_TEST_MODE__
785         debug_msg("Value : 0x%x", value);
786 #endif
787
788         if (value == 0x01) {
789 #ifdef __MMFILE_TEST_MODE__
790                 debug_msg("This has cdis tag and valid value");
791 #endif
792                 formatContext->cdis = 1;
793         } else {
794                 debug_error("This has cdis tag and but invalid value");
795                 goto exception;
796         }
797
798         return MMFILE_UTIL_SUCCESS;
799
800 exception:
801         mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
802
803         return MMFILE_UTIL_FAIL;
804 }
805
806 static int GetTagFromMetaBox(MMFileFormatContext *formatContext, MMFileIOHandle *fp, MMFILE_MP4_BASIC_BOX_HEADER *basic_header)
807 {
808         int readed = 0;
809         MMFILE_MP4_BASIC_BOX_HEADER hdlrBoxHeader = {0, };
810         MMFILE_MP4_BASIC_BOX_HEADER id3v2BoxHeader = {0, };
811         MMFILE_3GP_ID3V2_BOX id3v2Box = {0, };
812         AvFileContentInfo tagInfo = {0, };
813         unsigned char tagVersion = 0;
814         bool versionCheck = false;
815         int id3v2Len = 0;
816         unsigned int meta_version = 0;
817         MMFILE_3GP_HANDLER_BOX hdlrBox = {0, };
818         unsigned int encSize = 0;
819         int id3_meta = 0;
820 #ifdef ENABLE_ITUNES_META /* We don't support itunes meta now. so this is not defined yet */
821         int iTunes_meta = 0;
822 #endif
823
824         /* meta box */
825         readed = mmfile_read(fp, (unsigned char *)&meta_version, 4);
826         if (readed != 4) {
827                 debug_error("read meta box version\n");
828                 goto exception;
829         }
830
831         /* hdlr box */
832         readed = mmfile_read(fp, (unsigned char *)&hdlrBoxHeader, MMFILE_MP4_BASIC_BOX_HEADER_LEN);
833         if (readed != MMFILE_MP4_BASIC_BOX_HEADER_LEN) {
834                 debug_error("read hdlr box header\n");
835                 goto exception;
836         }
837
838         if (hdlrBoxHeader.type != FOURCC('h', 'd', 'l', 'r')) {
839                 debug_warning("meta type is not hdlr\n");
840                 goto exception;
841         }
842
843         hdlrBoxHeader.size = mmfile_io_be_uint32(hdlrBoxHeader.size);
844         hdlrBoxHeader.type = mmfile_io_le_uint32(hdlrBoxHeader.type);
845
846         readed = mmfile_read(fp, (unsigned char *)&hdlrBox, MMFILE_3GP_HANDLER_BOX_LEN);
847         if (readed != MMFILE_3GP_HANDLER_BOX_LEN) {
848                 debug_error("read hdlr box\n");
849                 goto exception;
850         }
851
852         hdlrBox.handler_type = mmfile_io_le_uint32(hdlrBox.handler_type);
853
854         /**
855          * check tag type (ID3v2 or iTunes)
856          */
857         if (hdlrBox.handler_type == FOURCC('I', 'D', '3', '2')) {
858 #ifdef __MMFILE_TEST_MODE__
859                 debug_msg("ID3v2 tag detected.\n");
860 #endif
861
862                 id3_meta = 1;
863 #ifdef ENABLE_ITUNES_META
864                 iTunes_meta = 0;
865 #endif
866         } else if (hdlrBox.handler_type == FOURCC('m', 'd', 'i', 'r') &&
867                    mmfile_io_le_uint32(hdlrBox.reserved[0]) == FOURCC('a', 'p', 'p', 'l')) {
868
869 #ifdef __MMFILE_TEST_MODE__
870                 debug_msg("Apple iTunes tag detected by mdir.\n");
871 #endif
872
873 #ifdef ENABLE_ITUNES_META
874                 iTunes_meta = 1;
875 #endif
876         } else {
877                 debug_warning("unknown meta type. 4CC:[%c%c%c%c]\n", ((char *)&hdlrBox.handler_type)[0],
878                               ((char *)&hdlrBox.handler_type)[1],
879                               ((char *)&hdlrBox.handler_type)[2],
880                               ((char *)&hdlrBox.handler_type)[3]);
881                 /*goto exception; */
882         }
883
884 #ifdef ENABLE_ITUNES_META
885         if (!id3_meta && !iTunes_meta) {
886                 /*Check ilst.
887                 APPLE meta data for iTunes reader = 'mdir.' so if handler type is 'mdir', this content may has itunes meta.
888                 most of contents has 'mdir' + 'appl'. but some contents just has 'mdir'
889                 but 'ilst' is meta for iTunes. so find 'ilst' is more correct to check if this contents has iTunes meta or not.*/
890
891                 const char *ilst_box = "ilst";
892                 int buf_size = strlen(ilst_box);
893
894                 unsigned char read_buf[buf_size + 1];
895                 memset(read_buf, 0x00, buf_size + 1);
896
897                 /* skip hdlr box */
898                 mmfile_seek(fp, hdlrBoxHeader.size - MMFILE_MP4_BASIC_BOX_HEADER_LEN - MMFILE_3GP_HANDLER_BOX_LEN + 4, SEEK_CUR);       /*+4 is hdlr size field */
899
900                 readed = mmfile_read(fp, read_buf, buf_size);   /* to find 'ilst' */
901                 if (readed != buf_size) {
902                         debug_error("read fail [%d]\n", readed);
903                         goto exception;
904                 }
905
906                 if (read_buf[0] == 'i' && read_buf[1] == 'l' && read_buf[2] == 's' && read_buf[3] == 't') {
907 #ifdef __MMFILE_TEST_MODE__
908                         debug_msg("Apple iTunes tag detected by ilst.\n");
909 #endif
910
911                         iTunes_meta = 1;
912                 }
913         }
914 #endif
915
916 #ifdef ENABLE_ITUNES_META
917         if (iTunes_meta) {
918                 /**
919                  * iTunes (Cover[?ovr] & Track[trkn] only extract!) + Genre/Artist : Added 2010.10.27,28
920                  *
921                  *  4cc   : 4byte
922                  *        : 4byte       size
923                  * 'data' : 4byte
924                  *        : 4byte       type
925                  *        : 4byte       unknown
926                  */
927 #define _ITUNES_READ_BUF_SZ             20
928 #define _ITUNES_TRACK_NUM_SZ    4
929 #define _ITUNES_GENRE_NUM_SZ    4
930 #define _ITUNES_COVER_TYPE_JPEG 13
931 #define _ITUNES_COVER_TYPE_PNG          14
932
933                 unsigned char read_buf[_ITUNES_READ_BUF_SZ];
934                 int i = 0;
935                 int cover_sz = 0, cover_type = 0, cover_found = 0;
936                 /* int track_found = 0; */ /* , track_num = 0; */
937                 /* int genre_found = 0; */ /* , genre_index = 0; */
938                 /* int artist_found = 0; */ /* , artist_sz = 0; */
939                 int limit = basic_header->size - hdlrBoxHeader.size;
940                 long long cover_offset = 0; /*, track_offset =0, genre_offset = 0, artist_offset = 0; */
941
942                 /* 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++) { */
943                 for (i = 0; (i < limit) && (cover_found == 0) ; i++) {
944                         readed = mmfile_read(fp, read_buf, _ITUNES_READ_BUF_SZ);
945                         if (readed != _ITUNES_READ_BUF_SZ)
946                                 goto exception;
947
948                         /*ffmpeg extract artist, tracknum, genre and cover image. see mov_read_udta_string().
949                         but ffmpeg does not support strange cover image.
950                         only support covr type 0xd(JPEG), 0xe(PNG), 0x1b(BMP). but we support other type*/
951 #if 0
952                         /**
953                          * Artist : Added 2010.10.28
954                          */
955                         if (artist_found == 0 &&
956                             read_buf[0] == 0xa9 && read_buf[1] == 'A' && read_buf[2] == 'R' && read_buf[3] == 'T' &&
957                             read_buf[8] == 'd' && read_buf[9] == 'a' && read_buf[10] == 't' && read_buf[11] == 'a') {
958
959                                 artist_found = 1;
960                                 artist_offset = mmfile_tell(fp);
961                                 artist_sz = mmfile_io_be_uint32(*(int *)(read_buf + 4)) - 16; /* atom len(4)+data(4)+atom verion(1)+flag(3)+null(4) = 16 */
962
963 #ifdef __MMFILE_TEST_MODE__
964                                 debug_msg("----------------------------------- artist found, offset=[%lld], size=[%d]\n", artist_offset, artist_sz);
965 #endif
966                         }
967
968                         /**
969                          * Track number
970                          */
971                         if (track_found == 0 &&
972                             read_buf[0] == 't' && read_buf[1] == 'r' && read_buf[2] == 'k' && read_buf[3] == 'n' &&
973                             read_buf[8] == 'd' && read_buf[9] == 'a' && read_buf[10] == 't' && read_buf[11] == 'a') {
974
975                                 track_found = 1;
976                                 track_offset = mmfile_tell(fp);
977
978 #ifdef __MMFILE_TEST_MODE__
979                                 debug_msg("----------------------------------- Track found, offset=[%lld]\n", track_offset);
980 #endif
981                         }
982
983                         /**
984                          * Genre : Added 2010.10.27
985                          */
986                         /*ffmpeg extract genre but only (0xa9,'g','e','n'). see mov_read_udta_string()*/
987                         if (genre_found == 0 &&
988                             read_buf[0] == 'g' && read_buf[1] == 'n' && read_buf[2] == 'r' && read_buf[3] == 'e' &&
989                             read_buf[8] == 'd' && read_buf[9] == 'a' && read_buf[10] == 't' && read_buf[11] == 'a') {
990
991                                 genre_found = 1;
992                                 genre_offset = mmfile_tell(fp);
993
994 #ifdef __MMFILE_TEST_MODE__
995                                 debug_msg("----------------------------------- genre found, offset=[%lld]\n", genre_offset);
996 #endif
997                         }
998 #endif
999
1000                         /**
1001                          * Cover image
1002                          */
1003
1004                         if (cover_found == 0 &&
1005                             read_buf[0] == 'c' && read_buf[1] == 'o' && read_buf[2] == 'v' && read_buf[3] == 'r' &&
1006                             read_buf[8] == 'd' && read_buf[9] == 'a' && read_buf[10] == 't' && read_buf[11] == 'a') {
1007
1008                                 cover_found = 1;
1009                                 cover_sz = mmfile_io_be_uint32(*(int *)(read_buf + 4)) - 12;
1010                                 cover_type = mmfile_io_be_uint32(*(int *)(read_buf + 12));
1011
1012                                 cover_offset = mmfile_tell(fp);
1013
1014 #ifdef __MMFILE_TEST_MODE__
1015                                 debug_msg("----------------------------------- cover_found found,  offset=[%lld]\n", cover_offset);
1016 #endif
1017                         }
1018
1019                         mmfile_seek(fp, -(_ITUNES_READ_BUF_SZ - 1), SEEK_CUR);  /*FIXME: poor search*/
1020                 } /*loop*/
1021
1022                 /*ffmpeg extract artist, tracknum, excep cover image. see mov_read_udta_string()*/
1023 #if 0
1024                 if (artist_found) {
1025                         if (artist_sz > 0) {
1026                                 mmfile_seek(fp, artist_offset, SEEK_SET);
1027
1028                                 if (formatContext->artist) {
1029 #ifdef __MMFILE_TEST_MODE__
1030                                         debug_msg("----------------------------------- previous artist was [%s] \n", formatContext->artist);
1031 #endif
1032                                         free(formatContext->artist);
1033                                 }
1034 #ifdef __MMFILE_TEST_MODE__
1035                                 debug_msg("----------------------------------- new artist will be allocated with size (len+1) [%d] \n", artist_sz + 1);
1036 #endif
1037                                 formatContext->artist = mmfile_malloc(artist_sz + 1);
1038
1039                                 if (formatContext->artist) {
1040                                         readed = mmfile_read(fp, (unsigned char *)formatContext->artist, artist_sz);
1041                                         formatContext->artist[artist_sz] = '\0';
1042
1043 #ifdef __MMFILE_TEST_MODE__
1044                                         debug_msg("----------------------------------- new artist is [%s] \n", formatContext->artist);
1045 #endif
1046
1047                                         if (readed != artist_sz) {
1048                                                 debug_error("failed to read. ret = %d, in = %d\n", readed, artist_sz);
1049                                                 mmfile_free(formatContext->artist);
1050                                         }
1051                                 }
1052                         }
1053                 }
1054
1055                 if (track_found) {
1056                         mmfile_seek(fp, track_offset, SEEK_SET);
1057                         readed = mmfile_read(fp, read_buf, _ITUNES_TRACK_NUM_SZ);
1058                         if (readed != _ITUNES_TRACK_NUM_SZ) {
1059                                 debug_error("failed to read. ret = %d, in = %d\n", readed, _ITUNES_TRACK_NUM_SZ);
1060                         } else {
1061                                 track_num = mmfile_io_be_uint32(*(int *)read_buf);
1062                                 if (!formatContext->tagTrackNum) {
1063                                         memset(read_buf, 0x00, _ITUNES_READ_BUF_SZ);
1064                                         snprintf((char *)read_buf, sizeof(read_buf), "%d", track_num);
1065                                         formatContext->tagTrackNum = mmfile_strdup((const char *)read_buf);
1066                                 }
1067                         }
1068                 }
1069
1070                 if (genre_found) {
1071                         mmfile_seek(fp, genre_offset, SEEK_SET);
1072                         readed = mmfile_read(fp, read_buf, _ITUNES_GENRE_NUM_SZ);
1073                         if (readed != _ITUNES_GENRE_NUM_SZ) {
1074                                 debug_error("failed to read. ret = %d, in = %d\n", readed, _ITUNES_GENRE_NUM_SZ);
1075                         } else {
1076                                 genre_index = mmfile_io_be_uint16(*(int *)read_buf);
1077 #ifdef __MMFILE_TEST_MODE__
1078                                 debug_msg("genre index=[%d] \n", genre_index);
1079 #endif
1080                                 if (genre_index > 0 && genre_index < GENRE_COUNT)       {
1081                                         if (!formatContext->genre) {
1082                                                 memset(read_buf, 0x00, _ITUNES_READ_BUF_SZ);
1083                                                 snprintf((char *)read_buf, sizeof(read_buf), "%s", MpegAudio_Genre[genre_index - 1]);
1084 #ifdef __MMFILE_TEST_MODE__
1085                                                 debug_msg("genre string=[%s] \n", read_buf);
1086 #endif
1087                                                 formatContext->genre = mmfile_strdup((const char *)read_buf);
1088                                         }
1089                                 }
1090                         }
1091                 }
1092 #endif
1093
1094                 /*
1095                         1) below spec is in "iTunes Package Asset Specification 4.3" published by apple.
1096                         Music Cover Art Image Profile
1097                         - TIFF with ".tif" extension (32-bit uncompressed), JPEG with ".jpg" extension (quality unconstrained), or PNG with ".png" extension
1098                         - RGB (screen standard)
1099                         - Minimum size of 600 x 600 pixels
1100                         - Images must be at least 72 dpi
1101
1102                         2)I found below info from google.
1103                         cover image flag : JPEG (13, 0xd), PNG (14, 0xe)
1104
1105                         3)So, FIXME when cover image format is tif!
1106                 */
1107                 if (cover_found) {
1108                         if (cover_sz > 0) {
1109                                 mmfile_seek(fp, cover_offset, SEEK_SET);
1110
1111                                 formatContext->artwork = mmfile_malloc(cover_sz);
1112                                 formatContext->artworkSize = cover_sz;
1113                                 if (cover_type == _ITUNES_COVER_TYPE_JPEG) {
1114                                         formatContext->artworkMime = mmfile_strdup("image/jpeg");
1115                                 } else if (cover_type == _ITUNES_COVER_TYPE_PNG) {
1116                                         formatContext->artworkMime = mmfile_strdup("image/png");
1117                                         /*} else if(cover_type == _ITUNES_COVER_TYPE_TIF) {
1118                                                 formatContext->artworkMime = mmfile_strdup("image/tif");*/
1119                                 } else {
1120                                         debug_warning("Not proper cover image type, but set to jpeg. cover_type[%d]", cover_type);
1121                                         formatContext->artworkMime = mmfile_strdup("image/jpeg");
1122                                 }
1123
1124                                 if (formatContext->artwork) {
1125                                         readed = mmfile_read(fp, formatContext->artwork, cover_sz);
1126                                         if (readed != cover_sz) {
1127                                                 debug_error("failed to read. ret = %d, in = %d\n", readed, cover_sz);
1128                                                 mmfile_free(formatContext->artwork);
1129                                                 formatContext->artworkSize = 0;
1130                                                 mmfile_free(formatContext->artworkMime);
1131                                         }
1132                                 }
1133                         }
1134                 }
1135
1136                 /*reset seek position*/
1137                 mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
1138
1139                 return MMFILE_UTIL_SUCCESS;
1140
1141         } else
1142 #endif
1143                 if (id3_meta) {
1144                         /**
1145                          * ID3v2
1146                          */
1147                         /* skip hdlr box name */
1148                         mmfile_seek(fp, hdlrBoxHeader.size - MMFILE_MP4_BASIC_BOX_HEADER_LEN - MMFILE_3GP_HANDLER_BOX_LEN, SEEK_CUR);
1149
1150                         /* id3 tag box */
1151                         readed = mmfile_read(fp, (unsigned char *)&id3v2BoxHeader, MMFILE_MP4_BASIC_BOX_HEADER_LEN);
1152                         if (readed != MMFILE_MP4_BASIC_BOX_HEADER_LEN) {
1153                                 debug_error("read id3v2 box header\n");
1154                                 goto exception;
1155                         }
1156
1157                         id3v2BoxHeader.size = mmfile_io_be_uint32(id3v2BoxHeader.size);
1158                         id3v2BoxHeader.type = mmfile_io_le_uint32(id3v2BoxHeader.type);
1159
1160                         if (id3v2BoxHeader.type != FOURCC('I', 'D', '3', '2')) {
1161                                 debug_warning("meta type is not id3v2\n");
1162                                 goto exception;
1163                         }
1164
1165                         readed = mmfile_read(fp, (unsigned char *)&id3v2Box, MMFILE_3GP_ID3V2_BOX_LEN);
1166                         if (readed != MMFILE_3GP_ID3V2_BOX_LEN) {
1167                                 debug_error("read id3v2 box\n");
1168                                 goto exception;
1169                         }
1170
1171                         id3v2Len = id3v2BoxHeader.size - MMFILE_MP4_BASIC_BOX_HEADER_LEN - MMFILE_3GP_ID3V2_BOX_LEN;
1172
1173                         id3v2Box.id3v2Data = mmfile_malloc(id3v2Len);
1174                         if (!id3v2Box.id3v2Data) {
1175                                 debug_error("malloc id3tag data error\n");
1176                                 goto exception;
1177                         }
1178
1179                         readed = mmfile_read(fp, (unsigned char *)id3v2Box.id3v2Data, id3v2Len);
1180                         if (readed != id3v2Len) {
1181                                 debug_error("read id3tag data error\n");
1182                                 goto exception;
1183                         }
1184
1185                         /* check id3v2 */
1186                         if (!IS_ID3V2_TAG(id3v2Box.id3v2Data)) {
1187                                 debug_error("it is not id3tag\n");
1188                                 goto exception;
1189                         }
1190
1191                         if (id3v2Box.id3v2Data[3] == 0xFF ||  id3v2Box.id3v2Data[4] == 0xFF ||
1192                             id3v2Box.id3v2Data[6] >= 0x80 ||  id3v2Box.id3v2Data[7] >= 0x80 ||
1193                             id3v2Box.id3v2Data[8] >= 0x80 ||  id3v2Box.id3v2Data[9] >= 0x80) {
1194                                 debug_error("it is not valid id3tag\n");
1195                                 goto exception;
1196                         }
1197
1198                         tagVersion = id3v2Box.id3v2Data[3];
1199                         if (tagVersion > 4) {
1200                                 debug_error("tag vesion is too high\n");
1201                                 goto exception;
1202                         }
1203
1204                         encSize = mmfile_io_le_uint32((unsigned int)&id3v2Box.id3v2Data[6]);
1205                         tagInfo.tagV2Info.tagLen = MP3_TAGv2_HEADER_LEN;
1206                         tagInfo.tagV2Info.tagLen += (((encSize & 0x0000007F) >> 0) | ((encSize & 0x00007F00) >> 1) | ((encSize & 0x007F0000) >> 2) | ((encSize & 0x7F000000) >> 3));
1207                         tagInfo.tagV2Info.tagVersion = tagVersion;
1208                         tagInfo.fileLen = id3v2Len;
1209
1210                         /* set id3v2 data to formatContext */
1211                         switch (tagVersion) {
1212                                 case 2: {
1213                                                 versionCheck = mm_file_id3tag_parse_v222(&tagInfo, id3v2Box.id3v2Data);
1214                                                 break;
1215                                         }
1216                                 case 3: {
1217                                                 versionCheck = mm_file_id3tag_parse_v223(&tagInfo, id3v2Box.id3v2Data);
1218                                                 break;
1219                                         }
1220                                 case 4: {
1221                                                 versionCheck = mm_file_id3tag_parse_v224(&tagInfo, id3v2Box.id3v2Data);
1222                                                 break;
1223                                         }
1224                                 case 1:
1225                                 default: {
1226                                                 debug_error("tag vesion is not support\n");
1227                                                 versionCheck = false;
1228                                                 break;
1229                                         }
1230                         }
1231
1232                         if (versionCheck == false) {
1233                                 debug_error("tag parsing is fail\n");
1234                                 goto exception;
1235                         }
1236
1237                         if (!formatContext->title)          formatContext->title = mmfile_strdup((const char *)tagInfo.pTitle);
1238                         if (!formatContext->artist)         formatContext->artist = mmfile_strdup((const char *)tagInfo.pArtist);
1239                         if (!formatContext->author)         formatContext->author = mmfile_strdup((const char *)tagInfo.pAuthor);
1240                         if (!formatContext->copyright)      formatContext->copyright = mmfile_strdup((const char *)tagInfo.pCopyright);
1241                         if (!formatContext->comment)        formatContext->comment = mmfile_strdup((const char *)tagInfo.pComment);
1242                         if (!formatContext->album)          formatContext->album = mmfile_strdup((const char *)tagInfo.pAlbum);
1243                         if (!formatContext->album_artist)   formatContext->album_artist = mmfile_strdup((const char *)tagInfo.pAlbum_Artist);
1244                         if (!formatContext->year)           formatContext->year = mmfile_strdup((const char *)tagInfo.pYear);
1245                         if (!formatContext->genre)          formatContext->genre = mmfile_strdup((const char *)tagInfo.pGenre);
1246                         if (!formatContext->tagTrackNum)    formatContext->tagTrackNum = mmfile_strdup((const char *)tagInfo.pTrackNum);
1247                         if (!formatContext->composer)       formatContext->composer = mmfile_strdup((const char *)tagInfo.pComposer);
1248                         if (!formatContext->classification) formatContext->classification = mmfile_strdup((const char *)tagInfo.pContentGroup);
1249                         if (!formatContext->conductor)      formatContext->conductor = mmfile_strdup((const char *)tagInfo.pConductor);
1250
1251                         formatContext->artwork = mmfile_malloc(tagInfo.imageInfo.imageLen);
1252                         if ((tagInfo.imageInfo.imageLen > 0) && formatContext->artwork) {
1253                                 formatContext->artworkSize = tagInfo.imageInfo.imageLen;
1254                                 memcpy(formatContext->artwork, tagInfo.imageInfo.pImageBuf, tagInfo.imageInfo.imageLen);
1255                         }
1256
1257                         mm_file_free_AvFileContentInfo(&tagInfo);
1258                         mmfile_free(id3v2Box.id3v2Data);
1259
1260                         /*reset seek position*/
1261                         mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
1262
1263                         return MMFILE_UTIL_SUCCESS;
1264
1265                 }
1266
1267
1268 exception:
1269         mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
1270         mmfile_free(id3v2Box.id3v2Data);
1271         mm_file_free_AvFileContentInfo(&tagInfo);
1272
1273         return MMFILE_UTIL_FAIL;
1274 }
1275
1276
1277 EXPORT_API int MMFileUtilGetMetaDataFromMP4(MMFileFormatContext *formatContext)
1278 {
1279         MMFileIOHandle *fp = NULL;
1280         int ret = 0;
1281         int readed;
1282
1283         ret = mmfile_open(&fp, formatContext->uriFileName, MMFILE_RDONLY);
1284         if (ret == MMFILE_UTIL_FAIL) {
1285                 debug_error("error: mmfile_open\n");
1286                 goto exit;
1287         }
1288
1289         MMFILE_MP4_BASIC_BOX_HEADER basic_header = {0, };
1290         basic_header.start_offset = mmfile_tell(fp);
1291
1292         while ((ret != MMFILE_UTIL_FAIL) && ((readed = mmfile_read(fp, (unsigned char *)&basic_header, MMFILE_MP4_BASIC_BOX_HEADER_LEN)) > 0)) {
1293                 basic_header.size = mmfile_io_be_uint32(basic_header.size);
1294                 basic_header.type = mmfile_io_le_uint32(basic_header.type);
1295
1296                 if (basic_header.size == 0) {
1297                         debug_warning("header is invalid.\n");
1298                         basic_header.size = readed;
1299                         basic_header.type = 0;
1300                 }
1301
1302 #ifdef __MMFILE_TEST_MODE__
1303                 debug_msg("START_OFFSET:[%lld] SIZE:[%d Byte] 4CC:[%c%c%c%c]\n",
1304                           basic_header.start_offset, basic_header.size,
1305                           ((char *)&basic_header.type)[0], ((char *)&basic_header.type)[1],
1306                           ((char *)&basic_header.type)[2], ((char *)&basic_header.type)[3]);
1307 #endif
1308
1309                 switch (basic_header.type) {
1310                         case FOURCC('m', 'o', 'o', 'v'): {
1311 #ifdef __MMFILE_TEST_MODE__
1312                                         debug_msg("MPEG4: [moov] SIZE: [%d]Byte\n", basic_header.size);
1313 #endif
1314                                         break;
1315                                 }
1316                         case FOURCC('u', 'd', 't', 'a'): {
1317 #ifdef __MMFILE_TEST_MODE__
1318                                         debug_msg("MPEG4: [udat] SIZE: [%d]Byte\n", basic_header.size);
1319 #endif
1320                                         break;
1321                                 }
1322                                 /*/////////////////////////////////////////////////////////////// */
1323                                 /*                  Extracting Tag Data                        // */
1324                                 /*/////////////////////////////////////////////////////////////// */
1325                         case FOURCC('t', 'i', 't', 'l'): {
1326 #ifdef __MMFILE_TEST_MODE__
1327                                         debug_msg("MPEG4: [titl] SIZE: [%d]Byte\n", basic_header.size);
1328 #endif
1329                                         GetStringFromTextTagBox(formatContext, fp, &basic_header, eMMFILE_3GP_TAG_TITLE);
1330                                         break;
1331                                 }
1332                         case FOURCC('d', 's', 'c', 'p'): {
1333 #ifdef __MMFILE_TEST_MODE__
1334                                         debug_msg("MPEG4: [dscp] SIZE: [%d]Byte\n", basic_header.size);
1335 #endif
1336                                         GetStringFromTextTagBox(formatContext, fp, &basic_header, eMMFILE_3GP_TAG_CAPTION);
1337                                         break;
1338                                 }
1339                         case FOURCC('c', 'p', 'r', 't'): {
1340 #ifdef __MMFILE_TEST_MODE__
1341                                         debug_msg("MPEG4: [cprt] SIZE: [%d]Byte\n", basic_header.size);
1342 #endif
1343                                         GetStringFromTextTagBox(formatContext, fp, &basic_header, eMMFILE_3GP_TAG_COPYRIGHT);
1344                                         break;
1345                                 }
1346                         case FOURCC('p', 'e', 'r', 'f'): {
1347 #ifdef __MMFILE_TEST_MODE__
1348                                         debug_msg("MPEG4: [perf] SIZE: [%d]Byte\n", basic_header.size);
1349 #endif
1350                                         GetStringFromTextTagBox(formatContext, fp, &basic_header, eMMFILE_3GP_TAG_PERFORMER);
1351                                         break;
1352                                 }
1353                         case FOURCC('a', 'u', 't', 'h'): {
1354 #ifdef __MMFILE_TEST_MODE__
1355                                         debug_msg("MPEG4: [auth] SIZE: [%d]Byte\n", basic_header.size);
1356 #endif
1357                                         GetStringFromTextTagBox(formatContext, fp, &basic_header, eMMFILE_3GP_TAG_AUTHOR);
1358                                         break;
1359                                 }
1360                         case FOURCC('g', 'n', 'r', 'e'): {
1361 #ifdef __MMFILE_TEST_MODE__
1362                                         debug_msg("MPEG4: [gnre] SIZE: [%d]Byte\n", basic_header.size);
1363 #endif
1364                                         GetStringFromTextTagBox(formatContext, fp, &basic_header, eMMFILE_3GP_TAG_GENRE);
1365                                         break;
1366                                 }
1367                         case FOURCC('a', 'l', 'b', 'm'): {
1368 #ifdef __MMFILE_TEST_MODE__
1369                                         debug_msg("MPEG4: [albm] SIZE: [%d]Byte\n", basic_header.size);
1370 #endif
1371                                         GetAlbumFromAlbumTagBox(formatContext, fp, &basic_header);
1372                                         break;
1373                                 }
1374                         case FOURCC('y', 'r', 'r', 'c'): {
1375 #ifdef __MMFILE_TEST_MODE__
1376                                         debug_msg("MPEG4: [yrrc] SIZE: [%d]Byte\n", basic_header.size);
1377 #endif
1378                                         GetYearFromYearTagBox(formatContext, fp, &basic_header);
1379                                         break;
1380                                 }
1381                         case FOURCC('r', 't', 'n', 'g'): {
1382 #ifdef __MMFILE_TEST_MODE__
1383                                         debug_msg("MPEG4: [rtng] SIZE: [%d]Byte\n", basic_header.size);
1384 #endif
1385                                         GetRatingFromRatingTagBox(formatContext, fp, &basic_header);  /* not use */
1386                                         break;
1387                                 }
1388                         case FOURCC('c', 'l', 's', 'f'): {
1389 #ifdef __MMFILE_TEST_MODE__
1390                                         debug_msg("MPEG4: [clsf] SIZE: [%d]Byte\n", basic_header.size);
1391 #endif
1392                                         GetClassficationFromClsfTagBox(formatContext, fp, &basic_header);
1393                                         break;
1394                                 }
1395                         case FOURCC('k', 'y', 'w', 'd'): {
1396 #ifdef __MMFILE_TEST_MODE__
1397                                         debug_msg("MPEG4: [kywd] SIZE: [%d]Byte\n", basic_header.size);
1398 #endif
1399                                         ret = mmfile_seek(fp, basic_header.start_offset + basic_header.size, SEEK_SET);
1400                                         break;
1401                                 }
1402                         case FOURCC('l', 'o', 'c', 'i'): {
1403 #ifdef __MMFILE_TEST_MODE__
1404                                         debug_msg("MPEG4: [loci] SIZE: [%d]Byte\n", basic_header.size);
1405 #endif
1406                                         GetLocationFromLociTagBox(formatContext, fp, &basic_header);
1407                                         break;
1408                                 }
1409                                 /* Check smta in user data field to be compatible with android */
1410                         case FOURCC('s', 'm', 't', 'a'): {
1411 #ifdef __MMFILE_TEST_MODE__
1412                                         debug_msg("MPEG4: [smta] SIZE: [%d]Byte\n", basic_header.size);
1413 #endif
1414                                         GetSAUTInfoFromSMTATagBox(formatContext, fp, &basic_header);
1415                                         break;
1416                                 }
1417                                 /* Check smta in user data field to be compatible with android */
1418                         case FOURCC('c', 'd', 'i', 's'): {
1419 #ifdef __MMFILE_TEST_MODE__
1420                                         debug_msg("MPEG4: [smta] SIZE: [%d]Byte\n", basic_header.size);
1421 #endif
1422                                         GetValueFromCDISTagBox(formatContext, fp, &basic_header);
1423                                         break;
1424                                 }
1425                                 /*/////////////////////////////////////////////////////////////// */
1426                                 /*                  Extracting ID3 Tag Data                    // */
1427                                 /*/////////////////////////////////////////////////////////////// */
1428                         case FOURCC('m', 'e', 't', 'a'): {
1429 #ifdef __MMFILE_TEST_MODE__
1430                                         debug_msg("MPEG4: [meta] SIZE: [%d]Byte\n", basic_header.size);
1431 #endif
1432                                         GetTagFromMetaBox(formatContext, fp, &basic_header);
1433                                         break;
1434                                 }
1435                         default: {
1436 #ifdef __MMFILE_TEST_MODE__
1437                                         debug_msg("4CC: Not Support.. so skip it\n");
1438 #endif
1439                                         ret = mmfile_seek(fp, basic_header.start_offset + basic_header.size, SEEK_SET);
1440                                         break;
1441                                 }
1442                 }
1443
1444                 if (ret == MMFILE_UTIL_FAIL) {
1445                         debug_error("mmfile operation is error\n");
1446                         ret = -1;
1447                         goto exit;
1448                 }
1449
1450                 basic_header.start_offset = mmfile_tell(fp);
1451         }
1452
1453 exit:
1454         mmfile_close(fp);
1455         return ret;
1456 }
1457
1458 static char *get_string(const char *buf, int buf_size, int *bytes_written)
1459 {
1460         int i = 0, c = 0;
1461         char *q = NULL;
1462         char str[512] = {0, };
1463
1464         q = str;
1465         for (i = 0; i < buf_size; i++) {
1466                 c = buf[i];
1467                 if (c == '\0')
1468                         break;
1469                 if ((q - str) >= (int)sizeof(str) - 1)
1470                         break;
1471                 *q++ = c;
1472         }
1473         *q = '\0';
1474
1475         if (strlen(str) > 0) {
1476                 *bytes_written = strlen(str);
1477                 return strdup(str);
1478         } else {
1479                 *bytes_written = 0;
1480                 return NULL;
1481         }
1482 }
1483
1484 static bool is_numeric(const char *buf, int buf_size)
1485 {
1486         int idx = 0;
1487         bool is_num = true;
1488
1489         for (idx = 0; idx < buf_size; idx++) {
1490                 if (isdigit((int)buf[idx])) {
1491                         continue;
1492                 } else {
1493                         is_num = false;
1494                         break;
1495                 }
1496         }
1497
1498         return is_num;
1499 }
1500
1501 char *rtrimN(char *pStr)
1502 {
1503         int pos = 0;
1504         pos = strlen(pStr) - 1;
1505         for (; pos >= 0; pos--) {
1506                 if (pStr[pos] == 0x20) {
1507                         pStr[pos] = 0x00;
1508                 } else {
1509                         break;
1510                 }
1511         }
1512
1513         return strdup(pStr);
1514 }
1515
1516 static bool make_characterset_array(char ***charset_array)
1517 {
1518         char *locale = MMFileUtilGetLocale(NULL);
1519
1520         *charset_array = calloc(AV_ID3V2_MAX, sizeof(char *));
1521
1522         if (*charset_array == NULL) {
1523                 debug_error("calloc failed ");
1524                 if (locale != NULL)
1525                         free(locale);
1526                 return false;
1527         }
1528
1529         if (locale != NULL) {
1530                 (*charset_array)[AV_ID3V2_ISO_8859] = strdup(locale);
1531         } else {
1532                 debug_error("get locale failed");
1533                 (*charset_array)[AV_ID3V2_ISO_8859] = NULL;
1534         }
1535
1536         (*charset_array)[AV_ID3V2_UTF16] = strdup("UCS2");
1537         (*charset_array)[AV_ID3V2_UTF16_BE] = strdup("UTF16-BE");
1538         (*charset_array)[AV_ID3V2_UTF8] = strdup("UTF-8");
1539
1540         return true;
1541 }
1542
1543 static bool release_characterset_array(char **charset_array)
1544 {
1545         int i = 0;
1546
1547         for (i = 0; i < AV_ID3V2_MAX; i++) {
1548                 if (charset_array[i] != NULL) {
1549                         free(charset_array[i]);
1550                         charset_array[i] = NULL;
1551                 }
1552         }
1553
1554         if (charset_array != NULL) {
1555                 free(charset_array);
1556                 charset_array = NULL;
1557         }
1558
1559         return true;
1560 }
1561
1562 static void init_content_info(AvFileContentInfo *pInfo)
1563 {
1564         pInfo->tagV2Info.bTitleMarked = false;
1565         pInfo->tagV2Info.bArtistMarked = false;
1566         pInfo->tagV2Info.bAlbumMarked = false;
1567         pInfo->tagV2Info.bAlbum_ArtistMarked = false;
1568         pInfo->tagV2Info.bYearMarked = false;
1569         pInfo->tagV2Info.bDescriptionMarked = false;
1570         pInfo->tagV2Info.bGenreMarked = false;
1571         pInfo->tagV2Info.bTrackNumMarked = false;
1572         pInfo->tagV2Info.bEncByMarked = false;
1573         pInfo->tagV2Info.bURLMarked = false;
1574         pInfo->tagV2Info.bCopyRightMarked = false;
1575         pInfo->tagV2Info.bOriginArtistMarked = false;
1576         pInfo->tagV2Info.bComposerMarked = false;
1577         pInfo->tagV2Info.bImageMarked = false;
1578
1579         pInfo->tagV2Info.bRecDateMarked = false;
1580         pInfo->tagV2Info.bContentGroupMarked = false;
1581
1582         pInfo->tagV2Info.bUnsyncLyricsMarked = false;
1583         pInfo->tagV2Info.bSyncLyricsMarked = false;
1584         pInfo->tagV2Info.bConductorMarked = false;
1585         pInfo->tagV2Info.bGenreUTF16 = false;
1586
1587         pInfo->imageInfo.bURLInfo = false;
1588         pInfo->imageInfo.pImageBuf = NULL;
1589         pInfo->imageInfo.imageLen = 0;
1590 }
1591
1592 EXPORT_API
1593 bool mm_file_id3tag_parse_v110(AvFileContentInfo *pInfo,  unsigned char *buffer)
1594 {
1595         const char *locale = MMFileUtilGetLocale(NULL);
1596         char *pFullStr = NULL;
1597
1598 #ifdef __MMFILE_TEST_MODE__
1599         debug_msg("ID3tag v110--------------------------------------------------------------\n");
1600 #endif
1601
1602         if (pInfo->tagV2Info.bTitleMarked == false) {
1603                 pFullStr = mmfile_string_convert((const char *)&buffer[3], MP3_ID3_TITLE_LENGTH, "UTF-8", locale, NULL, (unsigned int *)&pInfo->titleLen);
1604                 if (pFullStr != NULL) {
1605                         pInfo->pTitle = rtrimN(pFullStr);
1606                         free(pFullStr);
1607                 }
1608
1609 #ifdef __MMFILE_TEST_MODE__
1610                 debug_msg("pInfo->pTitle returned =(%s), pInfo->titleLen(%d)\n", pInfo->pTitle, pInfo->titleLen);
1611 #endif
1612         }
1613
1614         if (pInfo->tagV2Info.bArtistMarked == false) {
1615                 pFullStr = mmfile_string_convert((const char *)&buffer[33], MP3_ID3_ARTIST_LENGTH, "UTF-8", locale, NULL, (unsigned int *)&pInfo->artistLen);
1616                 if (pFullStr != NULL) {
1617                         pInfo->pArtist = rtrimN(pFullStr);
1618                         free(pFullStr);
1619                 }
1620
1621 #ifdef __MMFILE_TEST_MODE__
1622                 debug_msg("pInfo->pArtist returned =(%s), pInfo->artistLen(%d)\n", pInfo->pArtist, pInfo->artistLen);
1623 #endif
1624         }
1625
1626         if (pInfo->tagV2Info.bAlbumMarked == false) {
1627                 pFullStr = mmfile_string_convert((const char *)&buffer[63], MP3_ID3_ALBUM_LENGTH, "UTF-8", locale, NULL, (unsigned int *)&pInfo->albumLen);
1628                 if (pFullStr != NULL) {
1629                         pInfo->pAlbum = rtrimN(pFullStr);
1630                         free(pFullStr);
1631                 }
1632
1633 #ifdef __MMFILE_TEST_MODE__
1634                 debug_msg("pInfo->pAlbum returned =(%s), pInfo->albumLen(%d)\n", pInfo->pAlbum, pInfo->albumLen);
1635 #endif
1636         }
1637
1638         if (pInfo->tagV2Info.bYearMarked == false) {
1639
1640                 pInfo->pYear = mmfile_string_convert((const char *)&buffer[93], MP3_ID3_YEAR_LENGTH, "UTF-8", locale, NULL, (unsigned int *)&pInfo->yearLen);
1641 #ifdef __MMFILE_TEST_MODE__
1642                 debug_msg("pInfo->pYear returned =(%s), pInfo->yearLen(%d)\n", pInfo->pYear, pInfo->yearLen);
1643 #endif
1644
1645                 if (pInfo->pYear == NULL) {     /*Use same logic with ffmpeg*/
1646                         pInfo->pYear = get_string((const char *)&buffer[93], MP3_ID3_YEAR_LENGTH, (int *)&pInfo->yearLen);
1647 #ifdef __MMFILE_TEST_MODE__
1648                         debug_msg("pInfo->pYear returned =(%s), pInfo->yearLen(%d)\n", pInfo->pYear, pInfo->yearLen);
1649 #endif
1650                 }
1651         }
1652
1653         if (pInfo->tagV2Info.bDescriptionMarked == false) {
1654                 pInfo->pComment = mmfile_string_convert((const char *)&buffer[97], MP3_ID3_DESCRIPTION_LENGTH, "UTF-8", locale, NULL, (unsigned int *)&pInfo->commentLen);
1655 #ifdef __MMFILE_TEST_MODE__
1656                 debug_msg("pInfo->pComment returned =(%s), pInfo->commentLen(%d)\n", pInfo->pComment, pInfo->commentLen);
1657 #endif
1658
1659                 if (pInfo->pComment == NULL) {  /*Use same logic with ffmpeg*/
1660                         pInfo->pComment = get_string((const char *)&buffer[97], MP3_ID3_DESCRIPTION_LENGTH, (int *)&pInfo->commentLen);
1661 #ifdef __MMFILE_TEST_MODE__
1662                         debug_msg("pInfo->pComment returned =(%s), pInfo->commentLen(%d)\n", pInfo->pComment, pInfo->commentLen);
1663 #endif
1664                 }
1665         }
1666
1667         if (pInfo->tagV2Info.bTrackNumMarked == false) {
1668                 pInfo->pTrackNum = mmfile_malloc(5);
1669                 if (pInfo->pTrackNum != NULL) {
1670                         pInfo->pTrackNum[4] = 0;
1671                         snprintf(pInfo->pTrackNum, 4, "%04d", (int)buffer[126]);
1672                         pInfo->tracknumLen = strlen(pInfo->pTrackNum);
1673 #ifdef __MMFILE_TEST_MODE__
1674                         debug_msg("pInfo->pTrackNum returned =(%s), pInfo->tracknumLen(%d)\n", pInfo->pTrackNum, pInfo->tracknumLen);
1675 #endif
1676                 }
1677         }
1678
1679         if (pInfo->tagV2Info.bGenreMarked == false) {
1680                 pInfo->genre = buffer[127];
1681 #ifdef __MMFILE_TEST_MODE__
1682                 debug_msg("pInfo->genre returned genre number (%d)\n", pInfo->genre);
1683 #endif
1684         }
1685
1686         return true;
1687 }
1688
1689 EXPORT_API
1690 bool mm_file_id3tag_parse_v222(AvFileContentInfo *pInfo, unsigned char *buffer)
1691 {
1692         unsigned long taglen = 0;
1693         unsigned long needToloopv2taglen;
1694         unsigned long oneFrameLen = 0;
1695         unsigned long v2numOfFrames = 0;
1696         unsigned long curPos = 0;
1697         char CompTmp[4];
1698         char *pExtContent = NULL;
1699         unsigned long purelyFramelen = 0;
1700         unsigned int encodingOffSet = 0;
1701         int inx = 0, realCpyFrameNum = 0,
1702             /*checkImgMimeTypeMax = 0, */checkImgExtMax = 0,
1703             imgstartOffset = 0, tmp = 0;
1704
1705         int textEncodingType = 0;
1706
1707         char **charset_array = NULL;
1708
1709         make_characterset_array(&charset_array);
1710
1711         init_content_info(pInfo);
1712
1713         taglen = pInfo->tagV2Info.tagLen;
1714         needToloopv2taglen = taglen - MP3_TAGv2_HEADER_LEN;
1715         curPos = MP3_TAGv2_HEADER_LEN;
1716
1717 #ifdef __MMFILE_TEST_MODE__
1718         debug_msg("ID3tag v222--------------------------------------------------------------\n");
1719 #endif
1720         if (needToloopv2taglen - MP3_TAGv2_22_TXT_HEADER_LEN > MP3_TAGv2_22_TXT_HEADER_LEN) {
1721                 v2numOfFrames = 1;
1722                 while (needToloopv2taglen > MP3_TAGv2_22_TXT_HEADER_LEN) {
1723                         if ((buffer[curPos] < '0' || buffer[curPos] > 'Z') || (buffer[curPos + 1] < '0' || buffer[curPos + 1] > 'Z')
1724                             || (buffer[curPos + 2] < '0' || buffer[curPos + 2] > 'Z'))
1725                                 break;
1726
1727                         memcpy(CompTmp, &buffer[curPos], 3);
1728
1729                         CompTmp[3] = 0;
1730                         oneFrameLen = MP3_TAGv2_22_TXT_HEADER_LEN;
1731                         oneFrameLen += (unsigned long)buffer[3 + curPos] << 16 | (unsigned long)buffer[4 + curPos] << 8
1732                                        | (unsigned long)buffer[5 + curPos];
1733                         if (oneFrameLen > taglen - curPos)
1734                                 break;
1735                         purelyFramelen = oneFrameLen - MP3_TAGv2_22_TXT_HEADER_LEN;
1736                         curPos += MP3_TAGv2_22_TXT_HEADER_LEN;
1737
1738                         if (oneFrameLen > MP3_TAGv2_22_TXT_HEADER_LEN && purelyFramelen <= taglen - curPos) {
1739                                 curPos += purelyFramelen;
1740
1741                                 if (buffer[curPos - purelyFramelen] == 0x00) {
1742                                         encodingOffSet = 1;
1743                                         textEncodingType = AV_ID3V2_ISO_8859;
1744                                 } else if (buffer[curPos - purelyFramelen] == 0x01) {
1745                                         encodingOffSet = 1;
1746                                         textEncodingType = AV_ID3V2_UTF16;
1747                                 }
1748
1749                                 if (textEncodingType > AV_ID3V2_MAX) {
1750                                         debug_msg("WRONG ENCOIDNG TYPE [%d], FRAME[%s]\n", textEncodingType, (char *)CompTmp);
1751                                         continue;
1752                                 }
1753
1754                                 /*in order to deliver valid string to MP */
1755                                 while ((buffer[curPos - purelyFramelen + encodingOffSet] < 0x20) && (encodingOffSet < purelyFramelen))
1756                                         encodingOffSet++;
1757
1758                                 if (encodingOffSet < purelyFramelen) {
1759                                         realCpyFrameNum = purelyFramelen - encodingOffSet;
1760                                         pExtContent = mmfile_malloc(realCpyFrameNum + 3);
1761                                         memset(pExtContent, '\0', realCpyFrameNum + 3);
1762
1763                                         memcpy(pExtContent, &buffer[curPos - purelyFramelen + encodingOffSet], purelyFramelen - encodingOffSet);
1764
1765                                         if (realCpyFrameNum > 0) {
1766                                                 if (strncmp((char *)CompTmp, "TT2", 3) == 0 && pInfo->tagV2Info.bTitleMarked == false) {
1767                                                         pInfo->pTitle = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->titleLen);
1768
1769 #ifdef __MMFILE_TEST_MODE__
1770                                                         debug_msg("pInfo->pTitle returned = (%s), pInfo->titleLen(%d)\n", pInfo->pTitle, pInfo->titleLen);
1771 #endif
1772                                                         pInfo->tagV2Info.bTitleMarked = true;
1773                                                 } else if (strncmp((char *)CompTmp, "TP1", 3) == 0 && pInfo->tagV2Info.bArtistMarked == false) {
1774                                                         pInfo->pArtist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->artistLen);
1775
1776 #ifdef __MMFILE_TEST_MODE__
1777                                                         debug_msg("pInfo->pArtist returned = (%s), pInfo->artistLen(%d)\n", pInfo->pArtist, pInfo->artistLen);
1778 #endif
1779                                                         pInfo->tagV2Info.bArtistMarked = true;
1780                                                 } else if (strncmp((char *)CompTmp, "TP2", 3) == 0 && pInfo->tagV2Info.bAlbum_ArtistMarked == false) {
1781                                                         pInfo->pAlbum_Artist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->album_artistLen);
1782
1783 #ifdef __MMFILE_TEST_MODE__
1784                                                         debug_msg("pInfo->pAlbum_Artist returned = (%s), pInfo->album_artistLen(%d)\n", pInfo->pAlbum_Artist, pInfo->album_artistLen);
1785 #endif
1786                                                         pInfo->tagV2Info.bAlbum_ArtistMarked = true;
1787                                                 } else if (strncmp((char *)CompTmp, "TP3", 3) == 0 && pInfo->tagV2Info.bConductorMarked == false) {
1788                                                         pInfo->pConductor = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->conductorLen);
1789
1790 #ifdef __MMFILE_TEST_MODE__
1791                                                         debug_msg("pInfo->pConductor returned = (%s), pInfo->conductorLen(%d)\n", pInfo->pConductor, pInfo->conductorLen);
1792 #endif
1793                                                         pInfo->tagV2Info.bConductorMarked = true;
1794                                                 } else if (strncmp((char *)CompTmp, "TAL", 3) == 0 && pInfo->tagV2Info.bAlbumMarked == false) {
1795                                                         pInfo->pAlbum = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->albumLen);
1796
1797 #ifdef __MMFILE_TEST_MODE__
1798                                                         debug_msg("pInfo->pAlbum returned = (%s), pInfo->albumLen(%d)\n", pInfo->pAlbum, pInfo->albumLen);
1799 #endif
1800                                                         pInfo->tagV2Info.bAlbumMarked = true;
1801                                                 } else if (strncmp((char *)CompTmp, "TYE", 3) == 0 && pInfo->tagV2Info.bYearMarked == false) {
1802                                                         pInfo->pYear = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->yearLen);
1803
1804 #ifdef __MMFILE_TEST_MODE__
1805                                                         debug_msg("pInfo->pYear returned = (%s), pInfo->yearLen(%d)\n", pInfo->pYear, pInfo->yearLen);
1806 #endif
1807                                                         pInfo->tagV2Info.bYearMarked = true;
1808                                                 } else if (strncmp((char *)CompTmp, "COM", 3) == 0 && pInfo->tagV2Info.bDescriptionMarked == false) {
1809                                                         /*skip language data! */
1810                                                         if (realCpyFrameNum > 4) {
1811                                                                 realCpyFrameNum -= 4;
1812                                                                 tmp = 4;
1813
1814                                                                 /*pExtContent[tmp+1] value should't have encoding value */
1815                                                                 if (pExtContent[tmp] > 0x20 && (pExtContent[tmp - 1] == 0x00 || pExtContent[tmp - 1] == 0x01)) {
1816                                                                         if (pExtContent[tmp - 1] == 0x00)
1817                                                                                 textEncodingType = AV_ID3V2_ISO_8859;
1818                                                                         else
1819                                                                                 textEncodingType = AV_ID3V2_UTF16;
1820
1821                                                                         pInfo->pComment = mmfile_string_convert((char *)&pExtContent[tmp], realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->commentLen);
1822
1823 #ifdef __MMFILE_TEST_MODE__
1824                                                                         debug_msg("pInfo->pComment returned = (%s), pInfo->commentLen(%d)\n", pInfo->pComment, pInfo->commentLen);
1825 #endif
1826                                                                         pInfo->tagV2Info.bDescriptionMarked = true;
1827                                                                 } else {
1828 #ifdef __MMFILE_TEST_MODE__
1829                                                                         debug_msg("mmf_file_id3tag_parse_v222: failed to get Comment Info tmp(%d), purelyFramelen - encodingOffSet(%d)\n", tmp, purelyFramelen - encodingOffSet);
1830 #endif
1831                                                                 }
1832                                                         } else {
1833 #ifdef __MMFILE_TEST_MODE__
1834                                                                 debug_msg("mmf_file_id3tag_parse_v222: Description info too small to parse realCpyFrameNum(%d)\n", realCpyFrameNum);
1835 #endif
1836                                                         }
1837                                                         tmp = 0;
1838
1839                                                 } else if (strncmp((char *)CompTmp, "TCO", 3) == 0 && pInfo->tagV2Info.bGenreMarked == false) {
1840                                                         pInfo->pGenre = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->genreLen);
1841
1842 #ifdef __MMFILE_TEST_MODE__
1843                                                         debug_msg("pInfo->pGenre returned = (%s), pInfo->genreLen(%d)\n", pInfo->pGenre, pInfo->genreLen);
1844 #endif
1845
1846                                                         if ((pInfo->pGenre != NULL) && (pInfo->genreLen > 0)) {
1847                                                                 bool ret = FALSE;
1848                                                                 int int_genre = -1;
1849
1850                                                                 ret = is_numeric(pInfo->pGenre, pInfo->genreLen);
1851
1852                                                                 if (ret == TRUE) {
1853                                                                         sscanf(pInfo->pGenre, "%d", &int_genre);
1854 #ifdef __MMFILE_TEST_MODE__
1855                                                                         debug_msg("genre information is inteager [%d]\n", int_genre);
1856 #endif
1857
1858                                                                         /*Change int to string */
1859                                                                         if ((0 <= int_genre) && (int_genre < GENRE_COUNT - 1)) {
1860                                                                                 /*save genreinfo like "(123)". mm_file_id3tag_restore_content_info convert it to string*/
1861                                                                                 char tmp_genre[6] = {0, };      /*ex. "(123)+NULL"*/
1862                                                                                 int tmp_genre_len = 0;
1863
1864                                                                                 memset(tmp_genre, 0, 6);
1865                                                                                 snprintf(tmp_genre, sizeof(tmp_genre), "(%d)", int_genre);
1866
1867                                                                                 tmp_genre_len = strlen(tmp_genre);
1868                                                                                 if (tmp_genre_len > 0) {
1869                                                                                         if (pInfo->pGenre) _FREE_EX(pInfo->pGenre);
1870                                                                                         pInfo->pGenre = mmfile_malloc(sizeof(char) * (tmp_genre_len + 1));
1871                                                                                         if (pInfo->pGenre) {
1872                                                                                                 strncpy(pInfo->pGenre, tmp_genre, tmp_genre_len);
1873                                                                                                 pInfo->pGenre[tmp_genre_len] = 0;
1874                                                                                         }
1875                                                                                 }
1876                                                                         }
1877                                                                 }
1878                                                         }
1879
1880                                                         pInfo->tagV2Info.bGenreMarked = true;
1881                                                 } else if (strncmp((char *)CompTmp, "TRK", 3) == 0 && pInfo->tagV2Info.bTrackNumMarked == false) {
1882                                                         pInfo->pTrackNum = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->tracknumLen);
1883
1884 #ifdef __MMFILE_TEST_MODE__
1885                                                         debug_msg("pInfo->pTrackNum returned = (%s), pInfo->tracknumLen(%d)\n", pInfo->pTrackNum, pInfo->tracknumLen);
1886 #endif
1887                                                         pInfo->tagV2Info.bTrackNumMarked = true;
1888                                                 } else if (strncmp((char *)CompTmp, "TEN", 3) == 0 && pInfo->tagV2Info.bEncByMarked == false) {
1889                                                         pInfo->pEncBy = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->encbyLen);
1890
1891 #ifdef __MMFILE_TEST_MODE__
1892                                                         debug_msg("pInfo->pEncBy returned = (%s), pInfo->encbyLen(%d)\n", pInfo->pEncBy, pInfo->encbyLen);
1893 #endif
1894                                                         pInfo->tagV2Info.bEncByMarked = true;
1895                                                 } else if (strncmp((char *)CompTmp, "WXX", 3) == 0 && pInfo->tagV2Info.bURLMarked == false) {
1896                                                         if (realCpyFrameNum > 4) {
1897                                                                 /*skip language data! */
1898                                                                 realCpyFrameNum -= 4;
1899                                                                 tmp = 4;
1900
1901                                                                 /*pExtContent[tmp+1] value should't have null value */
1902                                                                 if (pExtContent[tmp] > 0x20 && (pExtContent[tmp - 1] == 0x00 || pExtContent[tmp - 1] == 0x01)) {
1903                                                                         if (pExtContent[tmp - 1] == 0x00)
1904                                                                                 textEncodingType = AV_ID3V2_ISO_8859;
1905                                                                         else
1906                                                                                 textEncodingType = AV_ID3V2_UTF16;
1907
1908                                                                         pInfo->pURL = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->urlLen);
1909
1910 #ifdef __MMFILE_TEST_MODE__
1911                                                                         debug_msg("pInfo->pURL returned = (%s), pInfo->urlLen(%d)\n", pInfo->pURL, pInfo->urlLen);
1912 #endif
1913                                                                         pInfo->tagV2Info.bURLMarked = true;
1914                                                                 } else {
1915 #ifdef __MMFILE_TEST_MODE__
1916                                                                         debug_msg("mmf_file_id3tag_parse_v222: failed to get URL Info tmp(%d), purelyFramelen - encodingOffSet(%d)\n", tmp, purelyFramelen - encodingOffSet);
1917 #endif
1918                                                                 }
1919                                                         } else {
1920 #ifdef __MMFILE_TEST_MODE__
1921                                                                 debug_msg("mmf_file_id3tag_parse_v222: URL info too small to parse realCpyFrameNum(%d)\n", realCpyFrameNum);
1922 #endif
1923                                                         }
1924                                                         tmp = 0;
1925                                                 } else if (strncmp((char *)CompTmp, "TCR", 3) == 0 && pInfo->tagV2Info.bCopyRightMarked == false) {
1926                                                         pInfo->pCopyright = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->copyrightLen);
1927
1928 #ifdef __MMFILE_TEST_MODE__
1929                                                         debug_msg("pInfo->pCopyright returned = (%s), pInfo->copyrightLen(%d)\n", pInfo->pCopyright, pInfo->copyrightLen);
1930 #endif
1931                                                         pInfo->tagV2Info.bCopyRightMarked = true;
1932                                                 } else if (strncmp((char *)CompTmp, "TOA", 3) == 0 && pInfo->tagV2Info.bOriginArtistMarked == false) {
1933                                                         pInfo->pOriginArtist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->originartistLen);
1934
1935 #ifdef __MMFILE_TEST_MODE__
1936                                                         debug_msg("pInfo->pOriginArtist returned = (%s), pInfo->originartistLen(%d)\n", pInfo->pOriginArtist, pInfo->originartistLen);
1937 #endif
1938                                                         pInfo->tagV2Info.bOriginArtistMarked = true;
1939                                                 } else if (strncmp((char *)CompTmp, "TCM", 3) == 0 && pInfo->tagV2Info.bComposerMarked == false) {
1940                                                         pInfo->pComposer = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->composerLen);
1941
1942 #ifdef __MMFILE_TEST_MODE__
1943                                                         debug_msg("pInfo->pComposer returned = (%s), pInfo->originartistLen(%d)\n", pInfo->pComposer, pInfo->composerLen);
1944 #endif
1945                                                         pInfo->tagV2Info.bComposerMarked = true;
1946                                                 } else if (strncmp((char *)CompTmp, "TRD", 3) == 0 && pInfo->tagV2Info.bRecDateMarked == false) {
1947                                                         pInfo->pRecDate = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->recdateLen);
1948
1949 #ifdef __MMFILE_TEST_MODE__
1950                                                         debug_msg("pInfo->pRecDate returned = (%s), pInfo->recdateLen(%d)\n", pInfo->pRecDate, pInfo->recdateLen);
1951 #endif
1952                                                         pInfo->tagV2Info.bRecDateMarked = true;
1953                                                 } else if (strncmp((char *)CompTmp, "PIC", 3) == 0 && pInfo->tagV2Info.bImageMarked == false && realCpyFrameNum <= 2000000) {
1954                                                         if (pExtContent[0] != 0) {
1955                                                                 for (inx = 0; inx < MP3_ID3_IMAGE_EXT_MAX_LENGTH; inx++)
1956                                                                         pInfo->imageInfo.imageExt[inx] = '\0';/*ini mimetype variable */
1957
1958                                                                 while ((checkImgExtMax < MP3_ID3_IMAGE_EXT_MAX_LENGTH - 1) && pExtContent[checkImgExtMax] != '\0') {
1959                                                                         pInfo->imageInfo.imageExt[checkImgExtMax] = pExtContent[checkImgExtMax];
1960                                                                         checkImgExtMax++;
1961                                                                 }
1962                                                         } else {
1963 #ifdef __MMFILE_TEST_MODE__
1964                                                                 debug_msg("mmf_file_id3tag_parse_v222: PIC image's not included to image Extention\n");
1965 #endif
1966                                                         }
1967
1968                                                         imgstartOffset += checkImgExtMax;
1969
1970                                                         if (pExtContent[imgstartOffset] < AV_ID3V2_PICTURE_TYPE_MAX) {
1971                                                                 pInfo->imageInfo.pictureType = pExtContent[imgstartOffset];
1972                                                         }
1973                                                         imgstartOffset++;/*PictureType(1byte) */
1974
1975                                                         if (pExtContent[imgstartOffset] != 0x0) {
1976                                                                 int cur_pos = 0;
1977                                                                 int dis_len = 0;
1978                                                                 int new_dis_len = 0;
1979                                                                 char jpg_sign[3] = {0xff, 0xd8, 0xff};
1980                                                                 char png_sign[8] = {0x80, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a};
1981                                                                 char *tmp_desc = NULL;
1982
1983                                                                 while (1) {
1984                                                                         if (pExtContent[imgstartOffset + cur_pos] == '\0') {
1985                                                                                 if (realCpyFrameNum < imgstartOffset + cur_pos) {
1986                                                                                         debug_error("End of APIC Tag %d %d %d\n", realCpyFrameNum, imgstartOffset, cur_pos);
1987                                                                                         break;
1988                                                                                 }
1989                                                                                 /*check end of image description*/
1990                                                                                 if ((pExtContent[imgstartOffset + cur_pos + 1] == jpg_sign[0]) ||
1991                                                                                     (pExtContent[imgstartOffset + cur_pos + 1] == png_sign[0])) {
1992 #ifdef __MMFILE_TEST_MODE__
1993                                                                                         debug_msg("length of description (%d)", cur_pos);
1994 #endif
1995
1996                                                                                         break;
1997                                                                                 }
1998                                                                         }
1999                                                                         cur_pos++;
2000                                                                 }
2001
2002                                                                 dis_len = cur_pos + 1;
2003
2004                                                                 tmp_desc = mmfile_malloc(sizeof(char) * dis_len);
2005
2006                                                                 if(tmp_desc != NULL) {
2007                                                                         memcpy(tmp_desc, pExtContent + imgstartOffset, dis_len);
2008
2009                                                                         /*convert description*/
2010                                                                         pInfo->imageInfo.imageDescription = mmfile_string_convert(tmp_desc, dis_len, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&new_dis_len);
2011                                                                         mmfile_free(tmp_desc);
2012
2013 #ifdef __MMFILE_TEST_MODE__
2014                                                                         debug_msg("new_desc %s(%d)\n", pInfo->imageInfo.imageDescription, new_dis_len);
2015 #endif
2016                                                                         pInfo->imageInfo.imgDesLen = new_dis_len; /**/
2017                                                                 }
2018
2019                                                                 imgstartOffset += cur_pos;
2020                                                         } else {
2021                                                                 pInfo->imageInfo.imgDesLen = 0;
2022                                                         }
2023
2024                                                         if ((pExtContent[imgstartOffset] == '\0') && (realCpyFrameNum - imgstartOffset > 0)) {
2025                                                                 imgstartOffset++; /* endofDesceriptionType(1byte) */
2026
2027                                                                 while (pExtContent[imgstartOffset] == '\0') {   /*some content has useless '\0' in front of picture data */
2028                                                                         imgstartOffset++;
2029                                                                 }
2030
2031 #ifdef __MMFILE_TEST_MODE__
2032                                                                 debug_msg("after scaning imgDescription imgstartOffset(%d) value!\n", imgstartOffset);
2033 #endif
2034
2035                                                                 if (realCpyFrameNum - imgstartOffset > 0) {
2036                                                                         pInfo->imageInfo.imageLen = realCpyFrameNum - imgstartOffset;
2037                                                                         pInfo->imageInfo.pImageBuf = mmfile_malloc(pInfo->imageInfo.imageLen + 1);
2038
2039                                                                         if (pInfo->imageInfo.pImageBuf != NULL) {
2040                                                                                 memcpy(pInfo->imageInfo.pImageBuf, pExtContent + imgstartOffset, pInfo->imageInfo.imageLen);
2041                                                                                 pInfo->imageInfo.pImageBuf[pInfo->imageInfo.imageLen] = 0;
2042                                                                         }
2043
2044                                                                         if (IS_INCLUDE_URL(pInfo->imageInfo.imageMIMEType))
2045                                                                                 pInfo->imageInfo.bURLInfo = true; /*if mimetype is "-->", image date has an URL */
2046                                                                 } else {
2047 #ifdef __MMFILE_TEST_MODE__
2048                                                                         debug_msg("No APIC image!! realCpyFrameNum(%d) - imgstartOffset(%d)\n", realCpyFrameNum, imgstartOffset);
2049 #endif
2050                                                                 }
2051                                                         }
2052
2053                                                         /*checkImgMimeTypeMax = 0;*/
2054                                                         checkImgExtMax = 0;
2055                                                         inx = 0;
2056                                                         imgstartOffset = 0;
2057                                                         pInfo->tagV2Info.bImageMarked = true;
2058
2059                                                 }
2060                                         }
2061
2062                                 }
2063                         } else {
2064                                 curPos += purelyFramelen;
2065                                 if (purelyFramelen != 0)
2066                                         needToloopv2taglen = MP3_TAGv2_22_TXT_HEADER_LEN;
2067                         }
2068
2069                         if (pExtContent)        _FREE_EX(pExtContent);
2070                         memset(CompTmp, 0, 4);
2071                         if (curPos < taglen) {
2072                                 needToloopv2taglen -= oneFrameLen;
2073                                 v2numOfFrames++;
2074                         } else
2075                                 needToloopv2taglen = MP3_TAGv2_22_TXT_HEADER_LEN;
2076                         oneFrameLen = 0;
2077                         encodingOffSet = 0;
2078                         realCpyFrameNum = 0;
2079                         textEncodingType = 0;
2080                         purelyFramelen = 0;
2081
2082                 }
2083         }
2084
2085         release_characterset_array(charset_array);
2086
2087         if (taglen) {
2088                 return true;
2089         } else {
2090                 return false;
2091         }
2092 }
2093
2094 EXPORT_API
2095 bool mm_file_id3tag_parse_v223(AvFileContentInfo *pInfo, unsigned char *buffer)
2096 {
2097         unsigned long taglen = 0;
2098         unsigned long needToloopv2taglen;
2099         unsigned long oneFrameLen = 0;
2100         unsigned long v2numOfFrames = 0;
2101         unsigned long curPos = 0;
2102         char CompTmp[5];
2103         unsigned char *pExtContent = NULL;
2104         unsigned long purelyFramelen = 0;
2105         unsigned int encodingOffSet = 0;
2106         int inx = 0, realCpyFrameNum = 0, checkImgMimeTypeMax = 0, imgstartOffset = 0,  tmp = 0;
2107         int textEncodingType = 0;
2108         char **charset_array = NULL;
2109         const char *MIME_PRFIX = "image/";
2110
2111         make_characterset_array(&charset_array);
2112
2113         init_content_info(pInfo);
2114
2115         taglen = pInfo->tagV2Info.tagLen;
2116         needToloopv2taglen = taglen - MP3_TAGv2_HEADER_LEN;
2117         curPos = MP3_TAGv2_HEADER_LEN;
2118
2119 #ifdef __MMFILE_TEST_MODE__
2120         debug_msg("ID3tag v223--------------------------------------------------------------\n");
2121 #endif
2122
2123         /* check Extended Header */
2124         if (buffer[5] & 0x40) {
2125                 /* if extended header exists, skip it*/
2126                 int extendedHeaderLen = (unsigned long)buffer[10] << 21 | (unsigned long)buffer[11] << 14 | (unsigned long)buffer[12] << 7  | (unsigned long)buffer[13];
2127
2128 #ifdef __MMFILE_TEST_MODE__
2129                 debug_msg("--------------- extendedHeaderLen = %d\n", extendedHeaderLen);
2130 #endif
2131
2132                 curPos += extendedHeaderLen;
2133                 curPos += 4;
2134         }
2135
2136         if (needToloopv2taglen - MP3_TAGv2_23_TXT_HEADER_LEN > MP3_TAGv2_23_TXT_HEADER_LEN) {
2137                 v2numOfFrames = 1;
2138                 while (needToloopv2taglen > MP3_TAGv2_23_TXT_HEADER_LEN) {
2139                         if ((buffer[curPos] < '0' || buffer[curPos] > 'Z') || (buffer[curPos + 1] < '0' || buffer[curPos + 1] > 'Z')
2140                             || (buffer[curPos + 2] < '0' || buffer[curPos + 2] > 'Z') || (buffer[curPos + 3] < '0' || buffer[curPos + 3] > 'Z'))
2141                                 break;
2142
2143                         memcpy(CompTmp, &buffer[curPos], 4);
2144
2145                         CompTmp[4] = 0;
2146                         oneFrameLen = MP3_TAGv2_23_TXT_HEADER_LEN;
2147                         oneFrameLen += (unsigned long)buffer[4 + curPos] << 24 | (unsigned long)buffer[5 + curPos] << 16
2148                                        | (unsigned long)buffer[6 + curPos] << 8 | (unsigned long)buffer[7 + curPos];
2149
2150 #ifdef __MMFILE_TEST_MODE__
2151                         debug_msg("----------------------------------------------------------------------------------------------------\n");
2152 #endif
2153
2154                         if (oneFrameLen > taglen - curPos)
2155                                 break;
2156
2157                         purelyFramelen = oneFrameLen - MP3_TAGv2_23_TXT_HEADER_LEN;
2158                         curPos += MP3_TAGv2_23_TXT_HEADER_LEN;
2159
2160                         if (oneFrameLen > MP3_TAGv2_23_TXT_HEADER_LEN && purelyFramelen <= taglen - curPos) {
2161                                 curPos += purelyFramelen;
2162
2163                                 if (IS_ENCODEDBY_UTF16(buffer + (curPos - purelyFramelen))) {
2164                                         encodingOffSet = 2;
2165 #ifdef __MMFILE_TEST_MODE__
2166                                         debug_msg("this text string(%s) encoded by UTF16 encodingOffSet(%d)\n", CompTmp, encodingOffSet);
2167 #endif
2168                                         textEncodingType = AV_ID3V2_UTF16;
2169                                 } else if (IS_ENCODEDBY_UTF16_R(buffer + (curPos - purelyFramelen))) {
2170                                         encodingOffSet = 2;
2171 #ifdef __MMFILE_TEST_MODE__
2172                                         debug_msg("this text string(%s) encoded by UTF16 encodingOffSet(%d)\n", CompTmp, encodingOffSet);
2173 #endif
2174                                         textEncodingType = AV_ID3V2_UTF16_BE;
2175                                 } else if (IS_ENCODEDBY_UTF16(buffer + (curPos - purelyFramelen + 1))) {
2176                                         encodingOffSet = 3;
2177 #ifdef __MMFILE_TEST_MODE__
2178                                         debug_msg("this text string(%s) encoded by UTF16 encodingOffSet(%d)\n", CompTmp, encodingOffSet);
2179 #endif
2180                                         textEncodingType = AV_ID3V2_UTF16;
2181                                 } else if (IS_ENCODEDBY_UTF16_R(buffer + (curPos - purelyFramelen + 1))) {
2182                                         encodingOffSet = 3;
2183 #ifdef __MMFILE_TEST_MODE__
2184                                         debug_msg("this text string(%s) encoded by UTF16 encodingOffSet(%d)\n", CompTmp, encodingOffSet);
2185 #endif
2186                                         textEncodingType = AV_ID3V2_UTF16_BE;
2187                                 } else {
2188                                         if (buffer[curPos - purelyFramelen + encodingOffSet] == 0x00) {
2189 #ifdef __MMFILE_TEST_MODE__
2190                                                 debug_msg("encodingOffset will be set to 1\n");
2191 #endif
2192
2193                                                 encodingOffSet = 1;
2194                                         } else {
2195 #ifdef __MMFILE_TEST_MODE__
2196                                                 debug_msg("Finding encodingOffset\n");
2197 #endif
2198
2199                                                 while ((buffer[curPos - purelyFramelen + encodingOffSet] < 0x20) && (encodingOffSet < purelyFramelen)) /* text string encoded by ISO-8859-1 */
2200                                                         encodingOffSet++;
2201                                         }
2202                                         textEncodingType = AV_ID3V2_ISO_8859;
2203 #ifdef __MMFILE_TEST_MODE__
2204                                         debug_msg("this text string(%s) encoded by ISO-8859-1 encodingOffSet(%d)\n", CompTmp, encodingOffSet);
2205 #endif
2206                                 }
2207
2208                                 if (encodingOffSet < purelyFramelen) {
2209                                         realCpyFrameNum = purelyFramelen - encodingOffSet;
2210                                         pExtContent = mmfile_malloc(realCpyFrameNum + 3);
2211                                         memset(pExtContent, '\0', realCpyFrameNum + 3);
2212
2213                                         if (textEncodingType != AV_ID3V2_UTF16 && textEncodingType != AV_ID3V2_UTF16_BE) {
2214                                                 if (CompTmp[0] == 'T' || (strcmp(CompTmp, "APIC") == 0)) {
2215 #ifdef __MMFILE_TEST_MODE__
2216                                                         debug_msg("get the new text ecoding type\n");
2217 #endif
2218                                                         textEncodingType = buffer[curPos - purelyFramelen + encodingOffSet - 1];
2219                                                 }
2220                                         }
2221
2222                                         if (textEncodingType > AV_ID3V2_MAX) {
2223                                                 debug_msg("WRONG ENCOIDNG TYPE [%d], FRAME[%s]\n", textEncodingType, (char *)CompTmp);
2224                                                 continue;
2225                                         }
2226
2227                                         memcpy(pExtContent, &buffer[curPos - purelyFramelen + encodingOffSet], purelyFramelen - encodingOffSet);
2228                                         if (realCpyFrameNum > 0) {
2229                                                 if (strncmp((char *)CompTmp, "TIT2", 4) == 0 && pInfo->tagV2Info.bTitleMarked == false) {
2230                                                         pInfo->pTitle = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->titleLen);
2231
2232 #ifdef __MMFILE_TEST_MODE__
2233                                                         debug_msg("pInfo->pTitle returned = (%s), pInfo->titleLen(%d)\n", pInfo->pTitle, pInfo->titleLen);
2234 #endif
2235                                                         pInfo->tagV2Info.bTitleMarked = true;
2236
2237                                                 } else if (strncmp((char *)CompTmp, "TPE1", 4) == 0 && pInfo->tagV2Info.bArtistMarked == false) {
2238                                                         pInfo->pArtist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->artistLen);
2239
2240 #ifdef __MMFILE_TEST_MODE__
2241                                                         debug_msg("pInfo->pArtist returned = (%s), pInfo->artistLen(%d)\n", pInfo->pArtist, pInfo->artistLen);
2242 #endif
2243                                                         pInfo->tagV2Info.bArtistMarked = true;
2244                                                 } else if (strncmp((char *)CompTmp, "TPE2", 4) == 0 && pInfo->tagV2Info.bAlbum_ArtistMarked == false) {
2245                                                         pInfo->pAlbum_Artist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->album_artistLen);
2246
2247 #ifdef __MMFILE_TEST_MODE__
2248                                                         debug_msg("pInfo->pAlbum_Artist returned = (%s), pInfo->album_artistLen(%d)\n", pInfo->pAlbum_Artist, pInfo->album_artistLen);
2249 #endif
2250                                                         pInfo->tagV2Info.bAlbum_ArtistMarked = true;
2251                                                 } else if (strncmp((char *)CompTmp, "TPE3", 4) == 0 && pInfo->tagV2Info.bConductorMarked == false) {
2252                                                         pInfo->pConductor = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->conductorLen);
2253
2254 #ifdef __MMFILE_TEST_MODE__
2255                                                         debug_msg("pInfo->pConductor returned = (%s), pInfo->conductorLen(%d)\n", pInfo->pConductor, pInfo->conductorLen);
2256 #endif
2257                                                         pInfo->tagV2Info.bConductorMarked = true;
2258                                                 } else if (strncmp((char *)CompTmp, "TALB", 4) == 0 && pInfo->tagV2Info.bAlbumMarked == false) {
2259                                                         pInfo->pAlbum = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->albumLen);
2260
2261 #ifdef __MMFILE_TEST_MODE__
2262                                                         debug_msg("pInfo->pAlbum returned = (%s), pInfo->albumLen(%d)\n", pInfo->pAlbum, pInfo->albumLen);
2263 #endif
2264                                                         pInfo->tagV2Info.bAlbumMarked = true;
2265                                                 } else if (strncmp((char *)CompTmp, "TYER", 4) == 0 && pInfo->tagV2Info.bYearMarked == false) {
2266                                                         pInfo->pYear = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->yearLen);
2267
2268 #ifdef __MMFILE_TEST_MODE__
2269                                                         debug_msg("pInfo->pYear returned = (%s), pInfo->yearLen(%d)\n", pInfo->pYear, pInfo->yearLen);
2270 #endif
2271                                                         pInfo->tagV2Info.bYearMarked = true;
2272                                                 } else if (strncmp((char *)CompTmp, "COMM", 4) == 0 && pInfo->tagV2Info.bDescriptionMarked == false) {
2273                                                         if (realCpyFrameNum > 3) {
2274                                                                 realCpyFrameNum -= 3;
2275                                                                 tmp = 3;
2276
2277                                                                 /*pExtContent[tmp+1] value should't have encoding value */
2278                                                                 if (pExtContent[tmp] == 0x00 || pExtContent[tmp] == 0xFF || pExtContent[tmp] == 0xFE) {
2279                                                                         if ((IS_ENCODEDBY_UTF16(pExtContent + tmp) || IS_ENCODEDBY_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 2) {
2280                                                                                 while ((NEWLINE_OF_UTF16(pExtContent + tmp) || NEWLINE_OF_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 4) {
2281                                                                                         realCpyFrameNum -= 4;
2282                                                                                         tmp += 4;
2283                                                                                 }
2284
2285                                                                                 if (IS_ENCODEDBY_UTF16(pExtContent + tmp) && (realCpyFrameNum > 2)) {
2286                                                                                         realCpyFrameNum -= 2;
2287                                                                                         tmp += 2;
2288                                                                                         textEncodingType = AV_ID3V2_UTF16;
2289                                                                                 } else if (IS_ENCODEDBY_UTF16_R(pExtContent + tmp) && (realCpyFrameNum > 2)) {
2290                                                                                         realCpyFrameNum -= 2;
2291                                                                                         tmp += 2;
2292                                                                                         textEncodingType = AV_ID3V2_UTF16_BE;
2293                                                                                 } else if (IS_ENCODEDBY_UTF16(pExtContent + tmp + 1) && (realCpyFrameNum > 3)) {
2294                                                                                         realCpyFrameNum -= 3;
2295                                                                                         tmp += 3;
2296                                                                                         textEncodingType = AV_ID3V2_UTF16;
2297                                                                                 } else if (IS_ENCODEDBY_UTF16_R(pExtContent + tmp + 1)  && (realCpyFrameNum > 3)) {
2298                                                                                         realCpyFrameNum -= 3;
2299                                                                                         tmp += 3;
2300                                                                                         textEncodingType = AV_ID3V2_UTF16_BE;
2301                                                                                 } else {
2302 #ifdef __MMFILE_TEST_MODE__
2303                                                                                         debug_msg("pInfo->pComment Never Get Here!!\n");
2304 #endif
2305                                                                                 }
2306                                                                         } else {
2307                                                                                 while ((pExtContent[tmp] < 0x20) && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
2308                                                                                         realCpyFrameNum--;
2309                                                                                         tmp++;
2310                                                                                 }
2311                                                                                 textEncodingType = AV_ID3V2_ISO_8859;
2312                                                                         }
2313
2314 #ifdef __MMFILE_TEST_MODE__
2315                                                                         debug_msg("tmp(%d) textEncodingType(%d), realCpyFrameNum(%d)\n", tmp, textEncodingType, realCpyFrameNum);
2316 #endif
2317
2318                                                                         pInfo->pComment = mmfile_string_convert((const char *)&pExtContent[tmp], realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->commentLen);
2319                                                                 } else {
2320 #ifdef __MMFILE_TEST_MODE__
2321                                                                         debug_msg("failed to get Comment Info tmp(%d), purelyFramelen - encodingOffSet(%d)\n", tmp, purelyFramelen - encodingOffSet);
2322 #endif
2323                                                                         pInfo->commentLen = 0;
2324                                                                 }
2325                                                         } else {
2326 #ifdef __MMFILE_TEST_MODE__
2327                                                                 debug_msg("Description info too small to parse realCpyFrameNum(%d)\n", realCpyFrameNum);
2328 #endif
2329                                                                 pInfo->commentLen = 0;
2330                                                         }
2331                                                         tmp = 0;
2332
2333 #ifdef __MMFILE_TEST_MODE__
2334                                                         debug_msg("pInfo->pComment returned = (%s), pInfo->commentLen(%d)\n", pInfo->pComment, pInfo->commentLen);
2335 #endif
2336                                                         pInfo->tagV2Info.bDescriptionMarked = true;
2337                                                 } else if (strncmp((char *)CompTmp, "SYLT", 4) == 0 && pInfo->tagV2Info.bSyncLyricsMarked == false) {
2338                                                         int idx = 0;
2339                                                         int copy_len = 0;
2340                                                         int copy_start_pos = tmp;
2341                                                         AvSynclyricsInfo *synclyrics_info = NULL;
2342                                                         GList *synclyrics_info_list = NULL;
2343
2344                                                         if (realCpyFrameNum > 5) {
2345                                                                 realCpyFrameNum -= 5;
2346                                                                 tmp = 5;
2347
2348                                                                 /*pExtContent[tmp+1] value should't have encoding value */
2349                                                                 if (pExtContent[tmp] == 0x00 || pExtContent[tmp] == 0xFF || pExtContent[tmp] == 0xFE) {
2350                                                                         if ((IS_ENCODEDBY_UTF16(pExtContent + tmp) || IS_ENCODEDBY_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 2) {
2351                                                                                 while ((NEWLINE_OF_UTF16(pExtContent + tmp) || NEWLINE_OF_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 4) {
2352                                                                                         realCpyFrameNum -= 4;
2353                                                                                         tmp += 4;
2354                                                                                 }
2355
2356                                                                                 if (IS_ENCODEDBY_UTF16(pExtContent + tmp) && (realCpyFrameNum > 2)) {
2357                                                                                         realCpyFrameNum -= 2;
2358                                                                                         tmp += 2;
2359                                                                                         textEncodingType = AV_ID3V2_UTF16;
2360                                                                                 } else if (IS_ENCODEDBY_UTF16_R(pExtContent + tmp) && (realCpyFrameNum > 2)) {
2361                                                                                         realCpyFrameNum -= 2;
2362                                                                                         tmp += 2;
2363                                                                                         textEncodingType = AV_ID3V2_UTF16_BE;
2364                                                                                 } else if (IS_ENCODEDBY_UTF16(pExtContent + tmp + 1) && (realCpyFrameNum > 3)) {
2365                                                                                         realCpyFrameNum -= 3;
2366                                                                                         tmp += 3;
2367                                                                                         textEncodingType = AV_ID3V2_UTF16;
2368                                                                                 } else if (IS_ENCODEDBY_UTF16_R(pExtContent + tmp + 1)  && (realCpyFrameNum > 3)) {
2369                                                                                         realCpyFrameNum -= 3;
2370                                                                                         tmp += 3;
2371                                                                                         textEncodingType = AV_ID3V2_UTF16_BE;
2372                                                                                 } else {
2373 #ifdef __MMFILE_TEST_MODE__
2374                                                                                         debug_msg("pInfo->pSyncLyrics Never Get Here!!\n");
2375 #endif
2376                                                                                 }
2377                                                                         } else {
2378                                                                                 while ((pExtContent[tmp] < 0x20) && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
2379                                                                                         realCpyFrameNum--;
2380                                                                                         tmp++;
2381                                                                                 }
2382                                                                                 textEncodingType = AV_ID3V2_ISO_8859;
2383                                                                         }
2384
2385 #ifdef __MMFILE_TEST_MODE__
2386                                                                         debug_msg("tmp(%d) textEncodingType(%d), realCpyFrameNum(%d)\n", tmp, textEncodingType, realCpyFrameNum);
2387 #endif
2388
2389                                                                         if (realCpyFrameNum < MMFILE_SYNC_LYRIC_INFO_MIN_LEN) {
2390 #ifdef __MMFILE_TEST_MODE__
2391                                                                                 debug_msg("failed to get Synchronised lyrics Info realCpyFramNum(%d)\n", realCpyFrameNum);
2392 #endif
2393                                                                                 pInfo->syncLyricsNum = 0;
2394                                                                         } else {
2395                                                                                 if (textEncodingType == AV_ID3V2_UTF16) {
2396                                                                                         debug_warning("[AV_ID3V2_UTF16] not implemented\n");
2397                                                                                 } else if (textEncodingType == AV_ID3V2_UTF16_BE) {
2398                                                                                         debug_warning("[AV_ID3V2_UTF16_BE] not implemented\n");
2399                                                                                 } else {
2400                                                                                         for (idx = 0; idx < realCpyFrameNum; idx++) {
2401                                                                                                 if (pExtContent[tmp + idx] == 0x00) {
2402                                                                                                         synclyrics_info = (AvSynclyricsInfo *)malloc(sizeof(AvSynclyricsInfo));
2403
2404                                                                                                         if (synclyrics_info != NULL) {
2405                                                                                                                 if (textEncodingType == AV_ID3V2_UTF8) {
2406                                                                                                                         synclyrics_info->lyric_info = mmfile_malloc(copy_len + 1);
2407                                                                                                                         if (synclyrics_info->lyric_info != NULL) {
2408                                                                                                                                 memset(synclyrics_info->lyric_info, 0, copy_len + 1);
2409                                                                                                                                 memcpy(synclyrics_info->lyric_info, pExtContent + copy_start_pos, copy_len);
2410                                                                                                                                 synclyrics_info->lyric_info[copy_len + 1] = '\0';
2411                                                                                                                         }
2412                                                                                                                 } else {
2413                                                                                                                         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);
2414                                                                                                                 }
2415
2416                                                                                                                 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];
2417                                                                                                                 idx += 4;
2418                                                                                                                 copy_start_pos = tmp + idx + 1;
2419 #ifdef __MMFILE_TEST_MODE__
2420                                                                                                                 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);
2421 #endif
2422                                                                                                                 copy_len = 0;
2423                                                                                                                 synclyrics_info_list = g_list_append(synclyrics_info_list, synclyrics_info);
2424                                                                                                         }
2425                                                                                                 }
2426                                                                                                 copy_len++;
2427                                                                                         }
2428                                                                                         pInfo->pSyncLyrics = synclyrics_info_list;
2429                                                                                         pInfo->syncLyricsNum = g_list_length(pInfo->pSyncLyrics);
2430                                                                                 }
2431                                                                         }
2432                                                                 } else {
2433 #ifdef __MMFILE_TEST_MODE__
2434                                                                         debug_msg("failed to get Synchronised lyrics Info tmp(%d), purelyFramelen - encodingOffSet(%d)\n", tmp, purelyFramelen - encodingOffSet);
2435 #endif
2436                                                                         pInfo->syncLyricsNum = 0;
2437                                                                 }
2438                                                         } else {
2439 #ifdef __MMFILE_TEST_MODE__
2440                                                                 debug_msg("Synchronised lyrics too small to parse realCpyFrameNum(%d)\n", realCpyFrameNum);
2441 #endif
2442                                                                 pInfo->syncLyricsNum = 0;
2443                                                         }
2444                                                         tmp = 0;
2445
2446 #ifdef __MMFILE_TEST_MODE__
2447                                                         debug_msg("pInfo->pSyncLyrics returned = (%s), pInfo->syncLyricsNum(%d)\n", pInfo->pSyncLyrics, pInfo->syncLyricsNum);
2448 #endif
2449                                                         pInfo->tagV2Info.bSyncLyricsMarked = true;
2450                                                 } else if (strncmp((char *)CompTmp, "USLT", 4) == 0 && pInfo->tagV2Info.bUnsyncLyricsMarked == false) {
2451                                                         char *lang_info = strndup((char *)pExtContent, 3);
2452
2453                                                         if (realCpyFrameNum > 3) {
2454                                                                 realCpyFrameNum -= 3;
2455                                                                 tmp = 3;
2456
2457                                                                 /*find start of lyrics */
2458                                                                 while (1) {
2459                                                                         if (pExtContent[tmp] == 0x00) {
2460                                                                                 if (pExtContent[tmp + 1] == 0x00) {
2461                                                                                         realCpyFrameNum -= 2;
2462                                                                                         tmp += 2;
2463                                                                                 }
2464                                                                                 break;
2465                                                                         } else {
2466                                                                                 realCpyFrameNum--;
2467                                                                                 tmp++;
2468                                                                         }
2469                                                                 }
2470
2471                                                                 /*pExtContent[tmp+1] value should't have encoding value */
2472 #ifdef __MMFILE_TEST_MODE__
2473                                                                 debug_msg("tpExtContent[%d] %x\n", tmp, pExtContent[tmp]);
2474 #endif
2475                                                                 if (pExtContent[tmp] == 0x00 || pExtContent[tmp] == 0xFF || pExtContent[tmp] == 0xFE) {
2476                                                                         if ((IS_ENCODEDBY_UTF16(pExtContent + tmp) || IS_ENCODEDBY_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 2) {
2477                                                                                 while ((NEWLINE_OF_UTF16(pExtContent + tmp) || NEWLINE_OF_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 4) {
2478                                                                                         realCpyFrameNum -= 4;
2479                                                                                         tmp += 4;
2480                                                                                 }
2481
2482                                                                                 if (IS_ENCODEDBY_UTF16(pExtContent + tmp) && (realCpyFrameNum > 2)) {
2483                                                                                         realCpyFrameNum -= 2;
2484                                                                                         tmp += 2;
2485                                                                                         textEncodingType = AV_ID3V2_UTF16;
2486                                                                                 } else if (IS_ENCODEDBY_UTF16_R(pExtContent + tmp) && (realCpyFrameNum > 2)) {
2487                                                                                         realCpyFrameNum -= 2;
2488                                                                                         tmp += 2;
2489                                                                                         textEncodingType = AV_ID3V2_UTF16_BE;
2490                                                                                 } else if (IS_ENCODEDBY_UTF16(pExtContent + tmp + 1) && (realCpyFrameNum > 3)) {
2491                                                                                         realCpyFrameNum -= 3;
2492                                                                                         tmp += 3;
2493                                                                                         textEncodingType = AV_ID3V2_UTF16;
2494                                                                                 } else if (IS_ENCODEDBY_UTF16_R(pExtContent + tmp + 1)  && (realCpyFrameNum > 3)) {
2495                                                                                         realCpyFrameNum -= 3;
2496                                                                                         tmp += 3;
2497                                                                                         textEncodingType = AV_ID3V2_UTF16_BE;
2498                                                                                 } else {
2499 #ifdef __MMFILE_TEST_MODE__
2500                                                                                         debug_msg("pInfo->pUnsyncLyrics Never Get Here!!\n");
2501 #endif
2502                                                                                 }
2503                                                                         } else {
2504                                                                                 while ((pExtContent[tmp] < 0x20) && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
2505                                                                                         realCpyFrameNum--;
2506                                                                                         tmp++;
2507                                                                                 }
2508                                                                                 textEncodingType = AV_ID3V2_ISO_8859;
2509                                                                         }
2510
2511 #ifdef __MMFILE_TEST_MODE__
2512                                                                         debug_msg("tmp(%d) textEncodingType(%d), realCpyFrameNum(%d)\n", tmp, textEncodingType, realCpyFrameNum);
2513 #endif
2514
2515                                                                         char *char_set = NULL;
2516                                                                         if (textEncodingType == AV_ID3V2_ISO_8859) {
2517                                                                                 if (lang_info != NULL && !strcasecmp(lang_info, "KOR")) {
2518                                                                                         char_set = strdup("EUC-KR");
2519                                                                                 } else {
2520                                                                                         char_set = mmfile_get_charset((const char *)&pExtContent[tmp]);
2521                                                                                 }
2522                                                                                 _FREE_EX(lang_info);
2523                                                                         }
2524
2525                                                                         if (char_set == NULL) {
2526                                                                                 pInfo->pUnsyncLyrics = mmfile_string_convert((const char *)&pExtContent[tmp], realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->unsynclyricsLen);
2527                                                                         } else {
2528                                                                                 pInfo->pUnsyncLyrics = mmfile_string_convert((const char *)&pExtContent[tmp], realCpyFrameNum, "UTF-8", char_set, NULL, (unsigned int *)&pInfo->unsynclyricsLen);
2529                                                                                 _FREE_EX(char_set);
2530                                                                         }
2531                                                                 } else {
2532 #ifdef __MMFILE_TEST_MODE__
2533                                                                         debug_msg("failed to get Unsynchronised lyrics Info tmp(%d), purelyFramelen - encodingOffSet(%d)\n", tmp, purelyFramelen - encodingOffSet);
2534 #endif
2535                                                                         pInfo->unsynclyricsLen = 0;
2536                                                                 }
2537                                                         } else {
2538 #ifdef __MMFILE_TEST_MODE__
2539                                                                 debug_msg("Unsynchronised lyrics too small to parse realCpyFrameNum(%d)\n", realCpyFrameNum);
2540 #endif
2541                                                                 pInfo->unsynclyricsLen = 0;
2542                                                         }
2543                                                         tmp = 0;
2544
2545 #ifdef __MMFILE_TEST_MODE__
2546                                                         debug_msg("pInfo->pUnsyncLyrics returned = (%s), pInfo->unsynclyricsLen(%d)\n", pInfo->pUnsyncLyrics, pInfo->unsynclyricsLen);
2547 #endif
2548                                                         pInfo->tagV2Info.bUnsyncLyricsMarked = true;
2549                                                         mmfile_free(lang_info);
2550                                                 } else if (strncmp((char *)CompTmp, "TCON", 4) == 0 && pInfo->tagV2Info.bGenreMarked == false) {
2551                                                         pInfo->pGenre = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->genreLen);
2552
2553 #ifdef __MMFILE_TEST_MODE__
2554                                                         debug_msg("pInfo->pGenre returned = (%s), pInfo->genreLen(%d)\n", pInfo->pGenre, pInfo->genreLen);
2555 #endif
2556
2557                                                         if ((pInfo->pGenre != NULL) && (pInfo->genreLen > 0)) {
2558                                                                 bool ret = FALSE;
2559                                                                 int int_genre = -1;
2560
2561                                                                 ret = is_numeric(pInfo->pGenre, pInfo->genreLen);
2562
2563                                                                 if (ret == TRUE) {
2564                                                                         sscanf(pInfo->pGenre, "%d", &int_genre);
2565 #ifdef __MMFILE_TEST_MODE__
2566                                                                         debug_msg("genre information is inteager [%d]\n", int_genre);
2567 #endif
2568
2569                                                                         /*Change int to string */
2570                                                                         if ((0 <= int_genre) && (int_genre < GENRE_COUNT - 1)) {
2571                                                                                 /*save genreinfo like "(123)". mm_file_id3tag_restore_content_info convert it to string*/
2572                                                                                 char tmp_genre[6] = {0, };      /*ex. "(123)+NULL"*/
2573                                                                                 int tmp_genre_len = 0;
2574
2575                                                                                 memset(tmp_genre, 0, 6);
2576                                                                                 snprintf(tmp_genre, sizeof(tmp_genre), "(%d)", int_genre);
2577
2578                                                                                 tmp_genre_len = strlen(tmp_genre);
2579                                                                                 if (tmp_genre_len > 0) {
2580                                                                                         if (pInfo->pGenre) _FREE_EX(pInfo->pGenre);
2581                                                                                         pInfo->pGenre = mmfile_malloc(sizeof(char) * (tmp_genre_len + 1));
2582                                                                                         if (pInfo->pGenre) {
2583                                                                                                 strncpy(pInfo->pGenre, tmp_genre, tmp_genre_len);
2584                                                                                                 pInfo->pGenre[tmp_genre_len] = 0;
2585                                                                                         }
2586                                                                                 }
2587                                                                         }
2588                                                                 }
2589                                                         }
2590
2591                                                         pInfo->tagV2Info.bGenreMarked = true;
2592                                                 } else if (strncmp((char *)CompTmp, "TRCK", 4) == 0 && pInfo->tagV2Info.bTrackNumMarked == false) {
2593                                                         pInfo->pTrackNum = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->tracknumLen);
2594
2595 #ifdef __MMFILE_TEST_MODE__
2596                                                         debug_msg("pInfo->pTrackNum returned = (%s), pInfo->tracknumLen(%d)\n", pInfo->pTrackNum, pInfo->tracknumLen);
2597 #endif
2598                                                         pInfo->tagV2Info.bTrackNumMarked = true;
2599                                                 } else if (strncmp((char *)CompTmp, "TENC", 4) == 0 && pInfo->tagV2Info.bEncByMarked == false) {
2600                                                         pInfo->pEncBy = mmfile_string_convert((char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->encbyLen);
2601
2602 #ifdef __MMFILE_TEST_MODE__
2603                                                         debug_msg("pInfo->pEncBy returned = (%s), pInfo->encbyLen(%d)\n", pInfo->pEncBy, pInfo->encbyLen);
2604 #endif
2605                                                         pInfo->tagV2Info.bEncByMarked = true;
2606                                                 } else if (strncmp((char *)CompTmp, "WXXX", 4) == 0 && pInfo->tagV2Info.bURLMarked == false) {
2607                                                         pInfo->pURL = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->urlLen);
2608
2609 #ifdef __MMFILE_TEST_MODE__
2610                                                         debug_msg("pInfo->pURL returned = (%s), pInfo->urlLen(%d)\n", pInfo->pURL, pInfo->urlLen);
2611 #endif
2612                                                         pInfo->tagV2Info.bURLMarked = true;
2613                                                 } else if (strncmp((char *)CompTmp, "TCOP", 4) == 0 && pInfo->tagV2Info.bCopyRightMarked == false) {
2614                                                         pInfo->pCopyright = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->copyrightLen);
2615
2616 #ifdef __MMFILE_TEST_MODE__
2617                                                         debug_msg("pInfo->pCopyright returned = (%s), pInfo->copyrightLen(%d)\n", pInfo->pCopyright, pInfo->copyrightLen);
2618 #endif
2619                                                         pInfo->tagV2Info.bCopyRightMarked = true;
2620                                                 } else if (strncmp((char *)CompTmp, "TOPE", 4) == 0 && pInfo->tagV2Info.bOriginArtistMarked == false) {
2621                                                         pInfo->pOriginArtist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->originartistLen);
2622
2623 #ifdef __MMFILE_TEST_MODE__
2624                                                         debug_msg("pInfo->pOriginArtist returned = (%s), pInfo->originartistLen(%d)\n", pInfo->pOriginArtist, pInfo->originartistLen);
2625 #endif
2626                                                         pInfo->tagV2Info.bOriginArtistMarked = true;
2627                                                 } else if (strncmp((char *)CompTmp, "TCOM", 4) == 0 && pInfo->tagV2Info.bComposerMarked == false) {
2628                                                         pInfo->pComposer = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->composerLen);
2629
2630 #ifdef __MMFILE_TEST_MODE__
2631                                                         debug_msg("pInfo->pComposer returned = (%s), pInfo->composerLen(%d)\n", pInfo->pComposer, pInfo->composerLen);
2632 #endif
2633                                                         pInfo->tagV2Info.bComposerMarked = true;
2634                                                 } else if (strncmp((char *)CompTmp, "TRDA", 4) == 0 && pInfo->tagV2Info.bRecDateMarked == false) {
2635                                                         pInfo->pRecDate = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->recdateLen);
2636
2637 #ifdef __MMFILE_TEST_MODE__
2638                                                         debug_msg("pInfo->pRecDate returned = (%s), pInfo->recdateLen(%d)\n", pInfo->pRecDate, pInfo->recdateLen);
2639 #endif
2640                                                         pInfo->tagV2Info.bRecDateMarked = true;
2641                                                 } else if (strncmp((char *)CompTmp, "APIC", 4) == 0 && pInfo->tagV2Info.bImageMarked == false && realCpyFrameNum <= 2000000) {
2642                                                         debug_msg("text encoding %d \n", textEncodingType);
2643
2644                                                         if (pExtContent[0] != '\0') {
2645                                                                 for (inx = 0; inx < MP3_ID3_IMAGE_MIME_TYPE_MAX_LENGTH - 1; inx++)
2646                                                                         pInfo->imageInfo.imageMIMEType[inx] = '\0';/*ini mimetype variable */
2647
2648                                                                 while ((checkImgMimeTypeMax < MP3_ID3_IMAGE_MIME_TYPE_MAX_LENGTH - 1) && pExtContent[checkImgMimeTypeMax] != '\0') {
2649                                                                         pInfo->imageInfo.imageMIMEType[checkImgMimeTypeMax] = pExtContent[checkImgMimeTypeMax];
2650                                                                         checkImgMimeTypeMax++;
2651                                                                 }
2652                                                                 pInfo->imageInfo.imgMimetypeLen = checkImgMimeTypeMax;
2653                                                         } else {
2654                                                                 pInfo->imageInfo.imgMimetypeLen = 0;
2655 #ifdef __MMFILE_TEST_MODE__
2656                                                                 debug_msg("APIC image's not included to MIME type\n");
2657 #endif
2658                                                         }
2659
2660                                                         imgstartOffset += checkImgMimeTypeMax;
2661
2662                                                         if (strncmp(pInfo->imageInfo.imageMIMEType, MIME_PRFIX, strlen(MIME_PRFIX)) != 0) {
2663                                                                 pInfo->imageInfo.imgMimetypeLen = 0;
2664                                                                 debug_error("APIC NOT VALID");
2665                                                                 continue;
2666                                                         }
2667
2668                                                         if ((pExtContent[imgstartOffset] == '\0') && (realCpyFrameNum - imgstartOffset > 0)) {
2669                                                                 imgstartOffset++;/*endofMIME(1byte) */
2670 #ifdef __MMFILE_TEST_MODE__
2671                                                                 debug_msg("after scaning Mime type imgstartOffset(%d) value!\n", imgstartOffset);
2672 #endif
2673
2674                                                                 if (pExtContent[imgstartOffset] < AV_ID3V2_PICTURE_TYPE_MAX) {
2675                                                                         pInfo->imageInfo.pictureType = pExtContent[imgstartOffset];
2676                                                                 } else {
2677 #ifdef __MMFILE_TEST_MODE__
2678                                                                         debug_msg("APIC image has invalid picture type(0x%x)\n", pExtContent[imgstartOffset]);
2679 #endif
2680                                                                 }
2681                                                                 imgstartOffset++;/*PictureType(1byte) */
2682 #ifdef __MMFILE_TEST_MODE__
2683                                                                 debug_msg("after scaning PictureType imgstartOffset(%d) value!\n", imgstartOffset);
2684 #endif
2685
2686                                                                 if (pExtContent[imgstartOffset] != 0x0) {
2687                                                                         int cur_pos = 0;
2688                                                                         int dis_len = 0;
2689                                                                         int new_dis_len = 0;
2690                                                                         char jpg_sign[3] = {0xff, 0xd8, 0xff};
2691                                                                         char png_sign[8] = {0x80, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a};
2692                                                                         char *tmp_desc = NULL;
2693
2694                                                                         while (1) {
2695                                                                                 if (pExtContent[imgstartOffset + cur_pos] == '\0') {
2696                                                                                         if (realCpyFrameNum < imgstartOffset + cur_pos) {
2697                                                                                                 debug_error("End of APIC Tag %d %d %d\n", realCpyFrameNum, imgstartOffset, cur_pos);
2698                                                                                                 break;
2699                                                                                         }
2700                                                                                         /*check end of image description*/
2701                                                                                         if ((pExtContent[imgstartOffset + cur_pos + 1] == jpg_sign[0]) ||
2702                                                                                             (pExtContent[imgstartOffset + cur_pos + 1] == png_sign[0])) {
2703 #ifdef __MMFILE_TEST_MODE__
2704                                                                                                 debug_msg("length of description (%d)", cur_pos);
2705 #endif
2706
2707                                                                                                 break;
2708                                                                                         }
2709                                                                                 }
2710                                                                                 cur_pos++;
2711                                                                         }
2712
2713                                                                         dis_len = cur_pos + 1;
2714
2715                                                                         tmp_desc = mmfile_malloc(sizeof(char) * dis_len);
2716                                                                         memcpy(tmp_desc, pExtContent + imgstartOffset, dis_len);
2717
2718                                                                         /*convert description*/
2719                                                                         pInfo->imageInfo.imageDescription = mmfile_string_convert(tmp_desc, dis_len, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&new_dis_len);
2720 #ifdef __MMFILE_TEST_MODE__
2721                                                                         debug_msg("new_desc %s(%d)\n", pInfo->imageInfo.imageDescription, new_dis_len);
2722 #endif
2723                                                                         mmfile_free(tmp_desc);
2724
2725                                                                         pInfo->imageInfo.imgDesLen = new_dis_len; /**/
2726                                                                         imgstartOffset += cur_pos;
2727                                                                 } else {
2728                                                                         pInfo->imageInfo.imgDesLen = 0;
2729 #ifdef __MMFILE_TEST_MODE__
2730                                                                         debug_msg("APIC image's not included to Description!!!\n");
2731 #endif
2732                                                                 }
2733
2734                                                                 if ((pExtContent[imgstartOffset] == '\0') && (realCpyFrameNum - imgstartOffset > 0)) {
2735                                                                         imgstartOffset++; /* endofDesceriptionType(1byte) */
2736
2737                                                                         while (pExtContent[imgstartOffset] == '\0') {   /*some content has useless '\0' in front of picture data */
2738                                                                                 imgstartOffset++;
2739                                                                         }
2740
2741 #ifdef __MMFILE_TEST_MODE__
2742                                                                         debug_msg("after scaning imgDescription imgstartOffset(%d) value!\n", imgstartOffset);
2743 #endif
2744
2745                                                                         if (realCpyFrameNum - imgstartOffset > 0) {
2746                                                                                 pInfo->imageInfo.imageLen = realCpyFrameNum - imgstartOffset;
2747                                                                                 pInfo->imageInfo.pImageBuf = mmfile_malloc(pInfo->imageInfo.imageLen + 1);
2748
2749                                                                                 if (pInfo->imageInfo.pImageBuf != NULL) {
2750                                                                                         memcpy(pInfo->imageInfo.pImageBuf, pExtContent + imgstartOffset, pInfo->imageInfo.imageLen);
2751                                                                                         pInfo->imageInfo.pImageBuf[pInfo->imageInfo.imageLen] = 0;
2752                                                                                 }
2753
2754                                                                                 if (IS_INCLUDE_URL(pInfo->imageInfo.imageMIMEType))
2755                                                                                         pInfo->imageInfo.bURLInfo = true; /*if mimetype is "-->", image date has an URL */
2756                                                                         } else {
2757 #ifdef __MMFILE_TEST_MODE__
2758                                                                                 debug_msg("No APIC image!! realCpyFrameNum(%d) - imgstartOffset(%d)\n", realCpyFrameNum, imgstartOffset);
2759 #endif
2760                                                                         }
2761 #ifdef __MMFILE_TEST_MODE__
2762                                                                         debug_msg("pInfo->imageInfo.imageLen(%d), imgstartOffset(%d)!\n", pInfo->imageInfo.imageLen, imgstartOffset);
2763 #endif
2764                                                                 } else {
2765 #ifdef __MMFILE_TEST_MODE__
2766                                                                         debug_msg("pExtContent[imgstartOffset](%d) value should setted NULL value for end of description! realCpyFrameNum - imgstartOffset(%d)\n",
2767                                                                                   pExtContent[imgstartOffset], realCpyFrameNum - imgstartOffset);
2768 #endif
2769                                                                 }
2770                                                         } else {
2771 #ifdef __MMFILE_TEST_MODE__
2772                                                                 debug_msg("pExtContent[imgstartOffset](%d) value should setted NULL value for end of mimetype! realCpyFrameNum - imgstartOffset(%d)\n",
2773                                                                           pExtContent[imgstartOffset], realCpyFrameNum - imgstartOffset);
2774 #endif
2775                                                         }
2776
2777                                                         checkImgMimeTypeMax = 0;
2778                                                         inx = 0;
2779                                                         imgstartOffset = 0;
2780                                                         pInfo->tagV2Info.bImageMarked = true;
2781
2782                                                 } else {
2783 #ifdef __MMFILE_TEST_MODE__
2784                                                         debug_msg("CompTmp(%s) This Frame ID currently not Supports!!\n", CompTmp);
2785 #endif
2786                                                 }
2787                                         }
2788
2789                                 } else {
2790 #ifdef __MMFILE_TEST_MODE__
2791                                         debug_msg("All of the pExtContent Values are NULL\n");
2792 #endif
2793                                 }
2794                         } else {
2795                                 curPos += purelyFramelen;
2796                                 if (purelyFramelen != 0)
2797                                         needToloopv2taglen = MP3_TAGv2_23_TXT_HEADER_LEN;
2798 #ifdef __MMFILE_TEST_MODE__
2799                                 debug_msg("This Frame's size is Zero! purelyFramelen(%d)\n", purelyFramelen);
2800 #endif
2801                         }
2802
2803                         if (pExtContent)        _FREE_EX(pExtContent);
2804                         memset(CompTmp, 0, 4);
2805
2806                         if (curPos < taglen) {
2807                                 needToloopv2taglen -= oneFrameLen;
2808                                 v2numOfFrames++;
2809                         } else
2810                                 needToloopv2taglen = MP3_TAGv2_23_TXT_HEADER_LEN;
2811                         oneFrameLen = 0;
2812                         encodingOffSet = 0;
2813                         realCpyFrameNum = 0;
2814                         textEncodingType = 0;
2815                         purelyFramelen = 0;
2816
2817                 }
2818         }
2819
2820         release_characterset_array(charset_array);
2821
2822         if (taglen)
2823                 return true;
2824         else
2825                 return false;
2826
2827 }
2828
2829 EXPORT_API
2830 bool mm_file_id3tag_parse_v224(AvFileContentInfo *pInfo, unsigned char *buffer)
2831 {
2832         unsigned long taglen = 0;
2833         unsigned long needToloopv2taglen;
2834         unsigned long oneFrameLen = 0;
2835         unsigned long v2numOfFrames = 0;
2836         unsigned long curPos = 0;
2837         char CompTmp[5];
2838         unsigned char *pExtContent = NULL;
2839         unsigned long purelyFramelen = 0;
2840         unsigned int encodingOffSet = 0;
2841         int inx = 0, realCpyFrameNum = 0, checkImgMimeTypeMax = 0, imgstartOffset = 0,  tmp = 0;
2842         int textEncodingType = 0;
2843         char **charset_array = NULL;
2844         const char *MIME_PRFIX = "image/";
2845
2846         make_characterset_array(&charset_array);
2847
2848         init_content_info(pInfo);
2849
2850         taglen = pInfo->tagV2Info.tagLen;
2851         needToloopv2taglen = taglen - MP3_TAGv2_HEADER_LEN;
2852         curPos = MP3_TAGv2_HEADER_LEN;
2853
2854 #ifdef __MMFILE_TEST_MODE__
2855         debug_msg("ID3tag v224--------------------------------------------------------------\n");
2856 #endif
2857
2858         /* check Extended Header */
2859         if (buffer[5] & 0x40) {
2860                 /* if extended header exists, skip it*/
2861                 int extendedHeaderLen = (unsigned long)buffer[10] << 21 | (unsigned long)buffer[11] << 14 | (unsigned long)buffer[12] << 7  | (unsigned long)buffer[13];
2862
2863 #ifdef __MMFILE_TEST_MODE__
2864                 debug_msg("--------------- extendedHeaderLen = %d\n", extendedHeaderLen);
2865 #endif
2866
2867                 curPos += extendedHeaderLen;
2868         }
2869
2870         if (needToloopv2taglen - MP3_TAGv2_23_TXT_HEADER_LEN > MP3_TAGv2_23_TXT_HEADER_LEN) {
2871                 v2numOfFrames = 1;
2872                 while (needToloopv2taglen > MP3_TAGv2_23_TXT_HEADER_LEN) {
2873                         if ((buffer[curPos] < '0' || buffer[curPos] > 'Z') || (buffer[curPos + 1] < '0' || buffer[curPos + 1] > 'Z')
2874                             || (buffer[curPos + 2] < '0' || buffer[curPos + 2] > 'Z') || (buffer[curPos + 3] < '0' || buffer[curPos + 3] > 'Z'))
2875                                 break;
2876
2877                         memcpy(CompTmp, &buffer[curPos], 4);
2878
2879                         CompTmp[4] = 0;
2880                         oneFrameLen = MP3_TAGv2_23_TXT_HEADER_LEN;
2881                         oneFrameLen += (unsigned long)buffer[4 + curPos] << 21 | (unsigned long)buffer[5 + curPos] << 14
2882                                        | (unsigned long)buffer[6 + curPos] << 7 | (unsigned long)buffer[7 + curPos];
2883                         if (oneFrameLen > taglen - curPos)
2884                                 break;
2885
2886                         purelyFramelen = oneFrameLen - MP3_TAGv2_23_TXT_HEADER_LEN;
2887                         curPos += MP3_TAGv2_23_TXT_HEADER_LEN;
2888
2889 #ifdef __MMFILE_TEST_MODE__
2890                         debug_msg("-----------------------------------------------------------------------------------\n");
2891 #endif
2892
2893                         if (oneFrameLen > MP3_TAGv2_23_TXT_HEADER_LEN && purelyFramelen <= taglen - curPos) {
2894                                 curPos += purelyFramelen;
2895
2896                                 /*in case of UTF 16 encoding */
2897                                 /*buffer+(curPos-purelyFramelen) data should '0x01' but in order to expansion, we don't accurately check the value. */
2898                                 if (IS_ENCODEDBY_UTF16(buffer + (curPos - purelyFramelen))) {
2899                                         encodingOffSet = 2;
2900                                         textEncodingType = AV_ID3V2_UTF16;
2901                                 } else if (IS_ENCODEDBY_UTF16_R(buffer + (curPos - purelyFramelen))) {
2902                                         encodingOffSet = 2;
2903                                         textEncodingType = AV_ID3V2_UTF16_BE;
2904                                 } else if (IS_ENCODEDBY_UTF16(buffer + (curPos - purelyFramelen + 1))) {
2905                                         encodingOffSet = 3;
2906                                         textEncodingType = AV_ID3V2_UTF16;
2907                                 } else if (IS_ENCODEDBY_UTF16_R(buffer + (curPos - purelyFramelen + 1))) {
2908                                         encodingOffSet = 3;
2909                                         textEncodingType = AV_ID3V2_UTF16_BE;
2910                                 } else {
2911                                         /*in case of UTF-16 BE encoding */
2912                                         if (buffer[curPos - purelyFramelen] == 0x02) {
2913                                                 encodingOffSet = 1;
2914                                                 while ((buffer[curPos - purelyFramelen + encodingOffSet] == '\0') && (encodingOffSet < purelyFramelen))
2915                                                         encodingOffSet++;/*null skip! */
2916                                                 textEncodingType = AV_ID3V2_UTF16_BE;
2917                                         }
2918                                         /*in case of UTF8 encoding */
2919                                         else if (buffer[curPos - purelyFramelen] == 0x03) {
2920                                                 encodingOffSet = 1;
2921                                                 while ((buffer[curPos - purelyFramelen + encodingOffSet] == '\0') && (encodingOffSet < purelyFramelen))
2922                                                         encodingOffSet++;/*null skip! */
2923                                                 textEncodingType = AV_ID3V2_UTF8;
2924                                         }
2925                                         /*in case of ISO-8859-1 encoding */
2926                                         else {
2927                                                 /*buffer+(curPos-purelyFramelen) data should 0x00 but in order to expansion, we don't accurately check the value. */
2928                                                 encodingOffSet = 1;
2929                                                 while ((buffer[curPos - purelyFramelen + encodingOffSet] < 0x20) && (encodingOffSet < purelyFramelen))
2930                                                         encodingOffSet++;/*less than 0x20 value skip! */
2931                                                 textEncodingType = AV_ID3V2_ISO_8859;
2932                                         }
2933                                 }
2934
2935                                 if (encodingOffSet < purelyFramelen) {
2936                                         realCpyFrameNum = purelyFramelen - encodingOffSet;
2937                                         pExtContent = mmfile_malloc(realCpyFrameNum + 3);
2938                                         memset(pExtContent, '\0', realCpyFrameNum + 3);
2939
2940                                         if (textEncodingType != AV_ID3V2_UTF16 && textEncodingType != AV_ID3V2_UTF16_BE) {
2941                                                 if (CompTmp[0] == 'T' || (strcmp(CompTmp, "APIC") == 0)) {
2942 #ifdef __MMFILE_TEST_MODE__
2943                                                         debug_msg("get the new text ecoding type\n");
2944 #endif
2945                                                         textEncodingType = buffer[curPos - purelyFramelen + encodingOffSet - 1];
2946                                                 }
2947                                         }
2948
2949                                         if (textEncodingType > AV_ID3V2_MAX) {
2950                                                 debug_msg("WRONG ENCOIDNG TYPE [%d], FRAME[%s]\n", textEncodingType, (char *)CompTmp);
2951                                                 continue;
2952                                         }
2953
2954                                         memcpy(pExtContent, &buffer[curPos - purelyFramelen + encodingOffSet], purelyFramelen - encodingOffSet);
2955
2956                                         if (realCpyFrameNum > 0) {
2957                                                 if (strncmp((char *)CompTmp, "TIT2", 4) == 0 && pInfo->tagV2Info.bTitleMarked == false) {
2958                                                         if (textEncodingType == AV_ID3V2_UTF8) {
2959                                                                 pInfo->pTitle = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
2960                                                                 memcpy(pInfo->pTitle, pExtContent, realCpyFrameNum);
2961                                                                 pInfo->pTitle[realCpyFrameNum] = '\0';
2962                                                                 /*string copy with '\0'*/
2963                                                                 pInfo->titleLen = realCpyFrameNum;
2964                                                                 _STRNCPY_EX(pInfo->pTitle, pExtContent, pInfo->titleLen);
2965                                                         } else {
2966                                                                 pInfo->pTitle = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->titleLen);
2967                                                         }
2968
2969 #ifdef __MMFILE_TEST_MODE__
2970                                                         debug_msg("pInfo->pTitle returned = (%s), pInfo->titleLen(%d)\n", pInfo->pTitle, pInfo->titleLen);
2971 #endif
2972                                                         pInfo->tagV2Info.bTitleMarked = true;
2973
2974                                                 } else if (strncmp((char *)CompTmp, "TPE1", 4) == 0 && pInfo->tagV2Info.bArtistMarked == false) {
2975                                                         if (textEncodingType == AV_ID3V2_UTF8) {
2976                                                                 pInfo->pArtist = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
2977                                                                 memcpy(pInfo->pArtist, pExtContent, realCpyFrameNum);
2978                                                                 pInfo->pArtist[realCpyFrameNum] = '\0';
2979                                                                 /*string copy with '\0'*/
2980                                                                 pInfo->artistLen = realCpyFrameNum;
2981                                                                 _STRNCPY_EX(pInfo->pArtist, pExtContent, pInfo->artistLen);
2982                                                         } else {
2983                                                                 pInfo->pArtist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->artistLen);
2984                                                         }
2985
2986 #ifdef __MMFILE_TEST_MODE__
2987                                                         debug_msg("pInfo->pArtist returned = (%s), pInfo->artistLen(%d)\n", pInfo->pArtist, pInfo->artistLen);
2988 #endif
2989                                                         pInfo->tagV2Info.bArtistMarked = true;
2990                                                 } else if (strncmp((char *)CompTmp, "TPE2", 4) == 0 && pInfo->tagV2Info.bAlbum_ArtistMarked == false) {
2991                                                         if (textEncodingType == AV_ID3V2_UTF8) {
2992                                                                 pInfo->pAlbum_Artist = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
2993                                                                 memcpy(pInfo->pAlbum_Artist, pExtContent, realCpyFrameNum);
2994                                                                 pInfo->pAlbum_Artist[realCpyFrameNum] = '\0';
2995                                                                 /*string copy with '\0'*/
2996                                                                 pInfo->album_artistLen = realCpyFrameNum;
2997                                                                 _STRNCPY_EX(pInfo->pAlbum_Artist, pExtContent, pInfo->album_artistLen);
2998                                                         } else {
2999                                                                 pInfo->pAlbum_Artist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->album_artistLen);
3000                                                         }
3001
3002 #ifdef __MMFILE_TEST_MODE__
3003                                                         debug_msg("pInfo->pAlbum_Artist returned = (%s), pInfo->album_artistLen(%d)\n", pInfo->pAlbum_Artist, pInfo->album_artistLen);
3004 #endif
3005                                                         pInfo->tagV2Info.bAlbum_ArtistMarked = true;
3006                                                 } else if (strncmp((char *)CompTmp, "TPE3", 4) == 0 && pInfo->tagV2Info.bConductorMarked == false) {
3007                                                         if (textEncodingType == AV_ID3V2_UTF8) {
3008                                                                 pInfo->pConductor = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3009                                                                 memcpy(pInfo->pConductor, pExtContent, realCpyFrameNum);
3010                                                                 pInfo->pConductor[realCpyFrameNum] = '\0';
3011                                                                 /*string copy with '\0'*/
3012                                                                 pInfo->conductorLen = realCpyFrameNum;
3013                                                                 _STRNCPY_EX(pInfo->pConductor, pExtContent, pInfo->conductorLen);
3014                                                         } else {
3015                                                                 pInfo->pConductor = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->conductorLen);
3016                                                         }
3017
3018 #ifdef __MMFILE_TEST_MODE__
3019                                                         debug_msg("pInfo->pConductor returned = (%s), pInfo->conductorLen(%d)\n", pInfo->pConductor, pInfo->conductorLen);
3020 #endif
3021                                                         pInfo->tagV2Info.bConductorMarked = true;
3022                                                 } else if (strncmp((char *)CompTmp, "TALB", 4) == 0 && pInfo->tagV2Info.bAlbumMarked == false) {
3023                                                         if (textEncodingType == AV_ID3V2_UTF8) {
3024                                                                 pInfo->pAlbum = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3025                                                                 memcpy(pInfo->pAlbum, pExtContent, realCpyFrameNum);
3026                                                                 pInfo->pAlbum[realCpyFrameNum] = '\0';
3027                                                                 /*string copy with '\0'*/
3028                                                                 pInfo->albumLen = realCpyFrameNum;
3029                                                                 _STRNCPY_EX(pInfo->pAlbum, pExtContent, pInfo->albumLen);
3030                                                         } else {
3031                                                                 pInfo->pAlbum = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->albumLen);
3032                                                         }
3033
3034 #ifdef __MMFILE_TEST_MODE__
3035                                                         debug_msg("pInfo->pAlbum returned = (%s), pInfo->albumLen(%d)\n", pInfo->pAlbum, pInfo->albumLen);
3036 #endif
3037                                                         pInfo->tagV2Info.bAlbumMarked = true;
3038                                                 } 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 */
3039                                                         if (textEncodingType == AV_ID3V2_UTF8) {
3040                                                                 pInfo->pYear = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3041                                                                 memcpy(pInfo->pYear, pExtContent, realCpyFrameNum);
3042                                                                 pInfo->pYear[realCpyFrameNum] = '\0';
3043                                                                 /*string copy with '\0'*/
3044                                                                 pInfo->yearLen = realCpyFrameNum;
3045                                                                 _STRNCPY_EX(pInfo->pYear, pExtContent, pInfo->yearLen);
3046                                                         } else {
3047                                                                 pInfo->pYear = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->yearLen);
3048                                                         }
3049
3050 #ifdef __MMFILE_TEST_MODE__
3051                                                         debug_msg("pInfo->pYear returned = (%s), pInfo->yearLen(%d)\n", pInfo->pYear, pInfo->yearLen);
3052 #endif
3053                                                         pInfo->tagV2Info.bYearMarked = true;
3054                                                 } else if (strncmp((char *)CompTmp, "COMM", 4) == 0 && pInfo->tagV2Info.bDescriptionMarked == false) {
3055                                                         if (realCpyFrameNum > 3) {
3056                                                                 realCpyFrameNum -= 3;
3057                                                                 tmp = 3;
3058
3059                                                                 if (textEncodingType == AV_ID3V2_UTF16 || textEncodingType == AV_ID3V2_UTF16_BE) {
3060                                                                         while ((NEWLINE_OF_UTF16(pExtContent + tmp) || NEWLINE_OF_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 4) {
3061                                                                                 realCpyFrameNum -= 4;
3062                                                                                 tmp += 4;
3063                                                                         }
3064
3065                                                                         if ((IS_ENCODEDBY_UTF16(pExtContent + tmp) || IS_ENCODEDBY_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 2) {
3066                                                                                 realCpyFrameNum -= 2;
3067                                                                                 tmp += 2;
3068                                                                                 textEncodingType = AV_ID3V2_UTF16;
3069                                                                         } else {
3070 #ifdef __MMFILE_TEST_MODE__
3071                                                                                 debug_msg("pInfo->pComment Never Get Here!!\n");
3072 #endif
3073                                                                         }
3074                                                                 } else if (textEncodingType == AV_ID3V2_UTF8) {
3075                                                                         while (pExtContent[tmp] < 0x20 && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
3076                                                                                 realCpyFrameNum--;
3077                                                                                 tmp++;
3078                                                                         }
3079                                                                         textEncodingType = AV_ID3V2_UTF8;
3080                                                                 } else {
3081                                                                         while (pExtContent[tmp] < 0x20 && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
3082                                                                                 realCpyFrameNum--;
3083                                                                                 tmp++;
3084                                                                         }
3085                                                                         textEncodingType = AV_ID3V2_ISO_8859;
3086                                                                 }
3087
3088 #ifdef __MMFILE_TEST_MODE__
3089                                                                 debug_msg("tmp(%d) textEncodingType(%d), realCpyFrameNum(%d)\n", tmp, textEncodingType, realCpyFrameNum);
3090 #endif
3091
3092                                                                 if (textEncodingType == AV_ID3V2_UTF8) {
3093                                                                         pInfo->pComment = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3094                                                                         memset(pInfo->pComment, 0, (realCpyFrameNum + 2));
3095                                                                         memcpy(pInfo->pComment, pExtContent + tmp, realCpyFrameNum);
3096                                                                         pInfo->pComment[realCpyFrameNum] = '\0';
3097                                                                         /*string copy with '\0'*/
3098                                                                         pInfo->commentLen = realCpyFrameNum;
3099                                                                         _STRNCPY_EX(pInfo->pComment, pExtContent, pInfo->commentLen);
3100                                                                 } else {
3101                                                                         pInfo->pComment = mmfile_string_convert((const char *)&pExtContent[tmp], realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->commentLen);
3102                                                                 }
3103                                                         } else {
3104 #ifdef __MMFILE_TEST_MODE__
3105                                                                 debug_msg("Description info too small to parse realCpyFrameNum(%d)\n", realCpyFrameNum);
3106 #endif
3107                                                         }
3108
3109                                                         tmp = 0;
3110
3111 #ifdef __MMFILE_TEST_MODE__
3112                                                         debug_msg("pInfo->pComment returned = (%s), pInfo->commentLen(%d)\n", pInfo->pComment, pInfo->commentLen);
3113 #endif
3114                                                         pInfo->tagV2Info.bDescriptionMarked = true;
3115                                                 } else if (strncmp((char *)CompTmp, "SYLT", 4) == 0 && pInfo->tagV2Info.bSyncLyricsMarked == false) {
3116                                                         int idx = 0;
3117                                                         int copy_len = 0;
3118                                                         int copy_start_pos = tmp;
3119                                                         AvSynclyricsInfo *synclyrics_info = NULL;
3120                                                         GList *synclyrics_info_list = NULL;
3121
3122                                                         if (realCpyFrameNum > 5) {
3123                                                                 realCpyFrameNum -= 5;
3124                                                                 tmp = 5;
3125
3126                                                                 if (textEncodingType == AV_ID3V2_UTF16 || textEncodingType == AV_ID3V2_UTF16_BE) {
3127                                                                         while ((NEWLINE_OF_UTF16(pExtContent + tmp) || NEWLINE_OF_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 4) {
3128                                                                                 realCpyFrameNum -= 4;
3129                                                                                 tmp += 4;
3130                                                                         }
3131
3132                                                                         if ((IS_ENCODEDBY_UTF16(pExtContent + tmp) || IS_ENCODEDBY_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 2) {
3133                                                                                 realCpyFrameNum -= 2;
3134                                                                                 tmp += 2;
3135                                                                                 textEncodingType = AV_ID3V2_UTF16;
3136                                                                         } else {
3137 #ifdef __MMFILE_TEST_MODE__
3138                                                                                 debug_msg("pInfo->pSyncLyrics Never Get Here!!\n");
3139 #endif
3140                                                                         }
3141                                                                 } else if (textEncodingType == AV_ID3V2_UTF8) {
3142                                                                         while (pExtContent[tmp] < 0x20 && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
3143                                                                                 realCpyFrameNum--;
3144                                                                                 tmp++;
3145                                                                         }
3146                                                                         textEncodingType = AV_ID3V2_UTF8;
3147                                                                 } else {
3148                                                                         while (pExtContent[tmp] < 0x20 && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
3149                                                                                 realCpyFrameNum--;
3150                                                                                 tmp++;
3151                                                                         }
3152                                                                         textEncodingType = AV_ID3V2_ISO_8859;
3153                                                                 }
3154
3155 #ifdef __MMFILE_TEST_MODE__
3156                                                                 debug_msg("tmp(%d) textEncodingType(%d), realCpyFrameNum(%d)\n", tmp, textEncodingType, realCpyFrameNum);
3157 #endif
3158
3159                                                                 if (realCpyFrameNum < MMFILE_SYNC_LYRIC_INFO_MIN_LEN) {
3160 #ifdef __MMFILE_TEST_MODE__
3161                                                                         debug_msg("failed to get Synchronised lyrics Info realCpyFramNum(%d)\n", realCpyFrameNum);
3162 #endif
3163                                                                         pInfo->syncLyricsNum = 0;
3164                                                                 } else {
3165                                                                         if (textEncodingType == AV_ID3V2_UTF16) {
3166                                                                                 debug_warning("[AV_ID3V2_UTF16] not implemented\n");
3167                                                                         } else if (textEncodingType == AV_ID3V2_UTF16_BE) {
3168                                                                                 debug_warning("[AV_ID3V2_UTF16_BE] not implemented\n");
3169                                                                         } else {
3170                                                                                 for (idx = 0; idx < realCpyFrameNum; idx++) {
3171                                                                                         if (pExtContent[tmp + idx] == 0x00) {
3172                                                                                                 synclyrics_info = (AvSynclyricsInfo *)malloc(sizeof(AvSynclyricsInfo));
3173
3174                                                                                                 if (textEncodingType == AV_ID3V2_UTF8) {
3175                                                                                                         synclyrics_info->lyric_info = mmfile_malloc(copy_len + 1);
3176                                                                                                         memset(synclyrics_info->lyric_info, 0, copy_len + 1);
3177                                                                                                         memcpy(synclyrics_info->lyric_info, pExtContent + copy_start_pos, copy_len);
3178                                                                                                         synclyrics_info->lyric_info[copy_len + 1] = '\0';
3179                                                                                                 } else {
3180                                                                                                         synclyrics_info->lyric_info = mmfile_string_convert((const char *)&pExtContent[copy_start_pos], copy_len, "UTF-8", charset_array[textEncodingType], NULL, NULL);
3181                                                                                                 }
3182
3183                                                                                                 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];
3184                                                                                                 idx += 4;
3185                                                                                                 copy_start_pos = tmp + idx + 1;
3186 #ifdef __MMFILE_TEST_MODE__
3187                                                                                                 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);
3188 #endif
3189                                                                                                 copy_len = 0;
3190                                                                                                 synclyrics_info_list = g_list_append(synclyrics_info_list, synclyrics_info);
3191                                                                                         }
3192                                                                                         copy_len++;
3193                                                                                 }
3194                                                                                 pInfo->pSyncLyrics = synclyrics_info_list;
3195                                                                                 pInfo->syncLyricsNum = g_list_length(pInfo->pSyncLyrics);
3196                                                                         }
3197                                                                 }
3198                                                         } else {
3199 #ifdef __MMFILE_TEST_MODE__
3200                                                                 debug_msg("SyncLyrics info too small to parse realCpyFrameNum(%d)\n", realCpyFrameNum);
3201 #endif
3202                                                         }
3203
3204                                                         tmp = 0;
3205                                                         pInfo->tagV2Info.bSyncLyricsMarked = true;
3206                                                 } else if (strncmp((char *)CompTmp, "USLT", 4) == 0 && pInfo->tagV2Info.bUnsyncLyricsMarked == false) {
3207                                                         if (realCpyFrameNum > 3) {
3208                                                                 realCpyFrameNum -= 3;
3209                                                                 tmp = 3;
3210
3211                                                                 if (textEncodingType == AV_ID3V2_UTF16 || textEncodingType == AV_ID3V2_UTF16_BE) {
3212                                                                         while ((NEWLINE_OF_UTF16(pExtContent + tmp) || NEWLINE_OF_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 4) {
3213                                                                                 realCpyFrameNum -= 4;
3214                                                                                 tmp += 4;
3215                                                                         }
3216
3217                                                                         if ((IS_ENCODEDBY_UTF16(pExtContent + tmp) || IS_ENCODEDBY_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 2) {
3218                                                                                 realCpyFrameNum -= 2;
3219                                                                                 tmp += 2;
3220                                                                                 textEncodingType = AV_ID3V2_UTF16;
3221                                                                         } else {
3222 #ifdef __MMFILE_TEST_MODE__
3223                                                                                 debug_msg("pInfo->pUnsyncLyrics Never Get Here!!\n");
3224 #endif
3225                                                                         }
3226                                                                 } else if (textEncodingType == AV_ID3V2_UTF8) {
3227                                                                         while (pExtContent[tmp] < 0x20 && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
3228                                                                                 realCpyFrameNum--;
3229                                                                                 tmp++;
3230                                                                         }
3231                                                                         textEncodingType = AV_ID3V2_UTF8;
3232                                                                 } else {
3233                                                                         while (pExtContent[tmp] < 0x20 && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
3234                                                                                 realCpyFrameNum--;
3235                                                                                 tmp++;
3236                                                                         }
3237                                                                         textEncodingType = AV_ID3V2_ISO_8859;
3238                                                                 }
3239
3240 #ifdef __MMFILE_TEST_MODE__
3241                                                                 debug_msg("tmp(%d) textEncodingType(%d), realCpyFrameNum(%d)\n", tmp, textEncodingType, realCpyFrameNum);
3242 #endif
3243
3244                                                                 if (textEncodingType == AV_ID3V2_UTF8) {
3245                                                                         pInfo->pUnsyncLyrics = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3246                                                                         memset(pInfo->pUnsyncLyrics, 0, (realCpyFrameNum + 2));
3247                                                                         memcpy(pInfo->pUnsyncLyrics, pExtContent + tmp, realCpyFrameNum);
3248                                                                         pInfo->pUnsyncLyrics[realCpyFrameNum] = '\0';
3249                                                                         /*string copy with '\0'*/
3250                                                                         pInfo->unsynclyricsLen = realCpyFrameNum;
3251                                                                         _STRNCPY_EX(pInfo->pUnsyncLyrics, pExtContent, pInfo->unsynclyricsLen);
3252                                                                 } else {
3253                                                                         pInfo->pUnsyncLyrics = mmfile_string_convert((const char *)&pExtContent[tmp], realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->unsynclyricsLen);
3254                                                                 }
3255                                                         } else {
3256 #ifdef __MMFILE_TEST_MODE__
3257                                                                 debug_msg("Description info too small to parse realCpyFrameNum(%d)\n", realCpyFrameNum);
3258 #endif
3259                                                         }
3260
3261                                                         tmp = 0;
3262
3263 #ifdef __MMFILE_TEST_MODE__
3264                                                         debug_msg("pInfo->pUnsyncLyrics returned = (%s), pInfo->unsynclyricsLen(%d)\n", pInfo->pUnsyncLyrics, pInfo->unsynclyricsLen);
3265 #endif
3266                                                         pInfo->tagV2Info.bDescriptionMarked = true;
3267                                                 } else if (strncmp((char *)CompTmp, "TCON", 4) == 0 && pInfo->tagV2Info.bGenreMarked == false) {
3268                                                         if (textEncodingType == AV_ID3V2_UTF8) {
3269                                                                 pInfo->pGenre = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3270                                                                 memcpy(pInfo->pGenre, pExtContent, realCpyFrameNum);
3271                                                                 pInfo->pGenre[realCpyFrameNum] = '\0';
3272                                                                 /*string copy with '\0'*/
3273                                                                 pInfo->genreLen = realCpyFrameNum;
3274                                                                 _STRNCPY_EX(pInfo->pGenre, pExtContent, pInfo->genreLen);
3275                                                         } else {
3276                                                                 pInfo->pGenre = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->genreLen);
3277                                                         }
3278
3279 #ifdef __MMFILE_TEST_MODE__
3280                                                         debug_msg("pInfo->pGenre returned = (%s), pInfo->genreLen(%d)\n", pInfo->pGenre, pInfo->genreLen);
3281 #endif
3282
3283                                                         if ((pInfo->pGenre != NULL) && (pInfo->genreLen > 0)) {
3284                                                                 bool ret = FALSE;
3285                                                                 int int_genre = -1;
3286
3287                                                                 ret = is_numeric(pInfo->pGenre, pInfo->genreLen);
3288
3289                                                                 if (ret == TRUE) {
3290                                                                         sscanf(pInfo->pGenre, "%d", &int_genre);
3291 #ifdef __MMFILE_TEST_MODE__
3292                                                                         debug_msg("genre information is inteager [%d]\n", int_genre);
3293 #endif
3294
3295                                                                         /*Change int to string */
3296                                                                         if ((0 <= int_genre) && (int_genre < GENRE_COUNT - 1)) {
3297                                                                                 /*save genreinfo like "(123)". mm_file_id3tag_restore_content_info convert it to string*/
3298                                                                                 char tmp_genre[6] = {0, };      /*ex. "(123)+NULL"*/
3299                                                                                 int tmp_genre_len = 0;
3300
3301                                                                                 memset(tmp_genre, 0, 6);
3302                                                                                 snprintf(tmp_genre, sizeof(tmp_genre), "(%d)", int_genre);
3303
3304                                                                                 tmp_genre_len = strlen(tmp_genre);
3305                                                                                 if (tmp_genre_len > 0) {
3306                                                                                         if (pInfo->pGenre) _FREE_EX(pInfo->pGenre);
3307                                                                                         pInfo->pGenre = mmfile_malloc(sizeof(char) * (tmp_genre_len + 1));
3308                                                                                         if (pInfo->pGenre) {
3309                                                                                                 strncpy(pInfo->pGenre, tmp_genre, tmp_genre_len);
3310                                                                                                 pInfo->pGenre[tmp_genre_len] = 0;
3311                                                                                         }
3312                                                                                 }
3313                                                                         }
3314                                                                 }
3315                                                         }
3316
3317                                                         pInfo->tagV2Info.bGenreMarked = true;
3318                                                 } else if (strncmp((char *)CompTmp, "TRCK", 4) == 0 && pInfo->tagV2Info.bTrackNumMarked == false) {
3319                                                         if (textEncodingType == AV_ID3V2_UTF8) {
3320                                                                 pInfo->pTrackNum = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3321                                                                 memcpy(pInfo->pTrackNum, pExtContent, realCpyFrameNum);
3322                                                                 pInfo->pTrackNum[realCpyFrameNum] = '\0';
3323                                                                 /*string copy with '\0'*/
3324                                                                 pInfo->tracknumLen = realCpyFrameNum;
3325                                                                 _STRNCPY_EX(pInfo->pTrackNum, pExtContent, pInfo->tracknumLen);
3326                                                         } else {
3327                                                                 pInfo->pTrackNum = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->tracknumLen);
3328                                                         }
3329
3330
3331 #ifdef __MMFILE_TEST_MODE__
3332                                                         debug_msg("pInfo->pTrackNum returned = (%s), pInfo->tracknumLen(%d)\n", pInfo->pTrackNum, pInfo->tracknumLen);
3333 #endif
3334                                                         pInfo->tagV2Info.bTrackNumMarked = true;
3335                                                 } else if (strncmp((char *)CompTmp, "TENC", 4) == 0 && pInfo->tagV2Info.bEncByMarked == false) {
3336                                                         if (textEncodingType == AV_ID3V2_UTF8) {
3337                                                                 pInfo->pEncBy = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3338                                                                 memcpy(pInfo->pEncBy, pExtContent, realCpyFrameNum);
3339                                                                 pInfo->pEncBy[realCpyFrameNum] = '\0';
3340                                                                 /*string copy with '\0'*/
3341                                                                 pInfo->encbyLen = realCpyFrameNum;
3342                                                                 _STRNCPY_EX(pInfo->pEncBy, pExtContent, pInfo->encbyLen);
3343                                                         } else {
3344                                                                 pInfo->pEncBy = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->encbyLen);
3345                                                         }
3346
3347 #ifdef __MMFILE_TEST_MODE__
3348                                                         debug_msg("pInfo->pEncBy returned = (%s), pInfo->encbyLen(%d)\n", pInfo->pEncBy, pInfo->encbyLen);
3349 #endif
3350                                                         pInfo->tagV2Info.bEncByMarked = true;
3351                                                 } else if (strncmp((char *)CompTmp, "WXXX", 4) == 0 && pInfo->tagV2Info.bURLMarked == false) {
3352                                                         if (textEncodingType == AV_ID3V2_UTF8) {
3353                                                                 pInfo->pURL = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3354                                                                 memcpy(pInfo->pURL, pExtContent, realCpyFrameNum);
3355                                                                 pInfo->pURL[realCpyFrameNum] = '\0';
3356                                                                 /*string copy with '\0'*/
3357                                                                 pInfo->urlLen = realCpyFrameNum;
3358                                                                 _STRNCPY_EX(pInfo->pURL, pExtContent, pInfo->urlLen);
3359                                                         } else {
3360                                                                 pInfo->pURL = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->urlLen);
3361                                                         }
3362
3363 #ifdef __MMFILE_TEST_MODE__
3364                                                         debug_msg("pInfo->pURL returned = (%s), pInfo->urlLen(%d)\n", pInfo->pURL, pInfo->urlLen);
3365 #endif
3366                                                         pInfo->tagV2Info.bURLMarked = true;
3367                                                 } else if (strncmp((char *)CompTmp, "TCOP", 4) == 0 && pInfo->tagV2Info.bCopyRightMarked == false) {
3368                                                         if (textEncodingType == AV_ID3V2_UTF8) {
3369                                                                 pInfo->pCopyright = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3370                                                                 memcpy(pInfo->pCopyright, pExtContent, realCpyFrameNum);
3371                                                                 pInfo->pCopyright[realCpyFrameNum] = '\0';
3372                                                                 /*string copy with '\0'*/
3373                                                                 pInfo->copyrightLen = realCpyFrameNum;
3374                                                                 _STRNCPY_EX(pInfo->pCopyright, pExtContent, pInfo->copyrightLen);
3375                                                         } else {
3376                                                                 pInfo->pCopyright = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->copyrightLen);
3377                                                         }
3378
3379 #ifdef __MMFILE_TEST_MODE__
3380                                                         debug_msg("pInfo->pCopyright returned = (%s), pInfo->copyrightLen(%d)\n", pInfo->pCopyright, pInfo->copyrightLen);
3381 #endif
3382                                                         pInfo->tagV2Info.bCopyRightMarked = true;
3383                                                 } else if (strncmp((char *)CompTmp, "TOPE", 4) == 0 && pInfo->tagV2Info.bOriginArtistMarked == false) {
3384                                                         if (textEncodingType == AV_ID3V2_UTF8) {
3385                                                                 pInfo->pOriginArtist = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3386                                                                 memcpy(pInfo->pOriginArtist, pExtContent, realCpyFrameNum);
3387                                                                 pInfo->pOriginArtist[realCpyFrameNum] = '\0';
3388                                                                 /*string copy with '\0'*/
3389                                                                 pInfo->originartistLen = realCpyFrameNum;
3390                                                                 _STRNCPY_EX(pInfo->pOriginArtist, pExtContent, pInfo->originartistLen);
3391                                                         } else {
3392                                                                 pInfo->pOriginArtist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->originartistLen);
3393                                                         }
3394
3395 #ifdef __MMFILE_TEST_MODE__
3396                                                         debug_msg("pInfo->pOriginArtist returned = (%s), pInfo->originartistLen(%d)\n", pInfo->pOriginArtist, pInfo->originartistLen);
3397 #endif
3398                                                         pInfo->tagV2Info.bOriginArtistMarked = true;
3399                                                 } else if (strncmp((char *)CompTmp, "TCOM", 4) == 0 && pInfo->tagV2Info.bComposerMarked == false) {
3400                                                         if (textEncodingType == AV_ID3V2_UTF8) {
3401                                                                 pInfo->pComposer = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3402                                                                 memcpy(pInfo->pComposer, pExtContent, realCpyFrameNum);
3403                                                                 pInfo->pComposer[realCpyFrameNum] = '\0';
3404                                                                 /*string copy with '\0'*/
3405                                                                 pInfo->composerLen = realCpyFrameNum;
3406                                                                 _STRNCPY_EX(pInfo->pComposer, pExtContent, pInfo->composerLen);
3407                                                         } else {
3408                                                                 pInfo->pComposer = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->composerLen);
3409                                                         }
3410
3411 #ifdef __MMFILE_TEST_MODE__
3412                                                         debug_msg("pInfo->pComposer returned = (%s), pInfo->originartistLen(%d)\n", pInfo->pComposer, pInfo->composerLen);
3413 #endif
3414                                                         pInfo->tagV2Info.bComposerMarked = true;
3415                                                 } else if (strncmp((char *)CompTmp, "TDRC", 4) == 0 && pInfo->tagV2Info.bRecDateMarked == false) {      /*TYER(year) and TRDA are replaced by the TDRC */
3416                                                         if (textEncodingType == AV_ID3V2_UTF8) {
3417                                                                 pInfo->pRecDate = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3418                                                                 memcpy(pInfo->pRecDate, pExtContent, realCpyFrameNum);
3419                                                                 pInfo->pRecDate[realCpyFrameNum] = '\0';
3420                                                                 /*string copy with '\0'*/
3421                                                                 pInfo->recdateLen = realCpyFrameNum;
3422                                                                 _STRNCPY_EX(pInfo->pRecDate, pExtContent, pInfo->recdateLen);
3423                                                         } else {
3424                                                                 pInfo->pRecDate = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->recdateLen);
3425                                                         }
3426
3427 #ifdef __MMFILE_TEST_MODE__
3428                                                         debug_msg("pInfo->pRecDate returned = (%s), pInfo->recdateLen(%d)\n", pInfo->pRecDate, pInfo->recdateLen);
3429 #endif
3430                                                         pInfo->tagV2Info.bRecDateMarked = true;
3431                                                 } else if (strncmp((char *)CompTmp, "TIT1", 4) == 0 && pInfo->tagV2Info.bContentGroupMarked == false) {
3432                                                         if (textEncodingType == AV_ID3V2_UTF8) {
3433                                                                 pInfo->pContentGroup = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3434                                                                 memcpy(pInfo->pContentGroup, pExtContent, realCpyFrameNum);
3435                                                                 pInfo->pContentGroup[realCpyFrameNum] = '\0';
3436                                                                 /*string copy with '\0'*/
3437                                                                 pInfo->contentGroupLen = realCpyFrameNum;
3438                                                                 _STRNCPY_EX(pInfo->pContentGroup, pExtContent, pInfo->contentGroupLen);
3439                                                         } else {
3440                                                                 pInfo->pContentGroup = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->contentGroupLen);
3441                                                         }
3442 #ifdef __MMFILE_TEST_MODE__
3443                                                         debug_msg("pInfo->pContentGroup returned = (%s), pInfo->contentGroupLen(%d)\n", pInfo->pContentGroup, pInfo->contentGroupLen);
3444 #endif
3445                                                         pInfo->tagV2Info.bContentGroupMarked = true;
3446                                                 } else if (strncmp((char *)CompTmp, "APIC", 4) == 0 && pInfo->tagV2Info.bImageMarked == false && realCpyFrameNum <= 2000000) {
3447                                                         if (pExtContent[0] != '\0') {
3448                                                                 for (inx = 0; inx < MP3_ID3_IMAGE_MIME_TYPE_MAX_LENGTH - 1; inx++)
3449                                                                         pInfo->imageInfo.imageMIMEType[inx] = '\0';/*ini mimetype variable */
3450
3451                                                                 while ((checkImgMimeTypeMax < MP3_ID3_IMAGE_MIME_TYPE_MAX_LENGTH - 1) && pExtContent[checkImgMimeTypeMax] != '\0') {
3452                                                                         pInfo->imageInfo.imageMIMEType[checkImgMimeTypeMax] = pExtContent[checkImgMimeTypeMax];
3453                                                                         checkImgMimeTypeMax++;
3454                                                                 }
3455                                                                 pInfo->imageInfo.imgMimetypeLen = checkImgMimeTypeMax;
3456                                                         } else {
3457                                                                 pInfo->imageInfo.imgMimetypeLen = 0;
3458                                                         }
3459
3460                                                         imgstartOffset += checkImgMimeTypeMax;
3461
3462                                                         if (strncmp(pInfo->imageInfo.imageMIMEType, MIME_PRFIX, strlen(MIME_PRFIX)) != 0) {
3463                                                                 pInfo->imageInfo.imgMimetypeLen = 0;
3464                                                                 debug_error("APIC NOT VALID");
3465                                                                 continue;
3466                                                         }
3467
3468                                                         if ((pExtContent[imgstartOffset] == '\0') && (realCpyFrameNum - imgstartOffset > 0)) {
3469                                                                 imgstartOffset++;/*endofMIME(1byte) */
3470
3471                                                                 if (pExtContent[imgstartOffset] < AV_ID3V2_PICTURE_TYPE_MAX) {
3472                                                                         pInfo->imageInfo.pictureType = pExtContent[imgstartOffset];
3473                                                                 }
3474                                                                 imgstartOffset++;/*PictureType(1byte) */
3475
3476                                                                 if (pExtContent[imgstartOffset] != 0x0) {
3477                                                                         int cur_pos = 0;
3478                                                                         int dis_len = 0;
3479                                                                         int new_dis_len = 0;
3480                                                                         char jpg_sign[3] = {0xff, 0xd8, 0xff};
3481                                                                         char png_sign[8] = {0x80, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a};
3482                                                                         char *tmp_desc = NULL;
3483
3484                                                                         while (1) {
3485                                                                                 if (pExtContent[imgstartOffset + cur_pos] == '\0') {
3486                                                                                         if (realCpyFrameNum < imgstartOffset + cur_pos) {
3487                                                                                                 debug_error("End of APIC Tag %d %d %d\n", realCpyFrameNum, imgstartOffset, cur_pos);
3488                                                                                                 break;
3489                                                                                         }
3490                                                                                         /*check end of image description*/
3491                                                                                         if ((pExtContent[imgstartOffset + cur_pos + 1] == jpg_sign[0]) ||
3492                                                                                             (pExtContent[imgstartOffset + cur_pos + 1] == png_sign[0])) {
3493 #ifdef __MMFILE_TEST_MODE__
3494                                                                                                 debug_msg("length of description (%d)", cur_pos);
3495 #endif
3496
3497                                                                                                 break;
3498                                                                                         }
3499                                                                                 }
3500                                                                                 cur_pos++;
3501                                                                         }
3502
3503                                                                         dis_len = cur_pos + 1;
3504
3505                                                                         tmp_desc = mmfile_malloc(sizeof(char) * dis_len);
3506
3507                                                                         if(tmp_desc != NULL) {
3508                                                                                 memcpy(tmp_desc, pExtContent + imgstartOffset, dis_len);
3509                                                                                 debug_msg("tmp_desc %s\n", tmp_desc);
3510
3511                                                                                 /*convert description*/
3512                                                                                 pInfo->imageInfo.imageDescription = mmfile_string_convert(tmp_desc, dis_len, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&new_dis_len);
3513                                                                                 debug_msg("new_desc %s(%d)\n", pInfo->imageInfo.imageDescription, new_dis_len);
3514                                                                                 mmfile_free(tmp_desc);
3515
3516                                                                                 pInfo->imageInfo.imgDesLen = new_dis_len; /**/
3517                                                                         }
3518
3519                                                                         imgstartOffset += cur_pos;
3520                                                                 } else {
3521                                                                         pInfo->imageInfo.imgDesLen = 0;
3522                                                                 }
3523
3524                                                                 if ((pExtContent[imgstartOffset] == '\0') && (realCpyFrameNum - imgstartOffset > 0)) {
3525                                                                         imgstartOffset++; /* endofDesceriptionType(1byte) */
3526
3527                                                                         while (pExtContent[imgstartOffset] == '\0') {   /*some content has useless '\0' in front of picture data */
3528                                                                                 imgstartOffset++;
3529                                                                         }
3530
3531 #ifdef __MMFILE_TEST_MODE__
3532                                                                         debug_msg("after scaning imgDescription imgstartOffset(%d) value!\n", imgstartOffset);
3533 #endif
3534
3535                                                                         if (realCpyFrameNum - imgstartOffset > 0) {
3536                                                                                 pInfo->imageInfo.imageLen = realCpyFrameNum - imgstartOffset;
3537                                                                                 pInfo->imageInfo.pImageBuf = mmfile_malloc(pInfo->imageInfo.imageLen + 1);
3538
3539                                                                                 if (pInfo->imageInfo.pImageBuf != NULL) {
3540                                                                                         memcpy(pInfo->imageInfo.pImageBuf, pExtContent + imgstartOffset, pInfo->imageInfo.imageLen);
3541                                                                                         pInfo->imageInfo.pImageBuf[pInfo->imageInfo.imageLen] = 0;
3542                                                                                 }
3543
3544                                                                                 if (IS_INCLUDE_URL(pInfo->imageInfo.imageMIMEType))
3545                                                                                         pInfo->imageInfo.bURLInfo = true; /*if mimetype is "-->", image date has an URL */
3546                                                                         } else {
3547 #ifdef __MMFILE_TEST_MODE__
3548                                                                                 debug_msg("No APIC image!! realCpyFrameNum(%d) - imgstartOffset(%d)\n", realCpyFrameNum, imgstartOffset);
3549 #endif
3550                                                                         }
3551                                                                 }
3552                                                         }
3553
3554                                                         checkImgMimeTypeMax = 0;
3555                                                         inx = 0;
3556                                                         imgstartOffset = 0;
3557                                                         pInfo->tagV2Info.bImageMarked = true;
3558                                                 } else {
3559 #ifdef __MMFILE_TEST_MODE__
3560                                                         debug_msg("CompTmp(%s) This Frame ID currently not Supports!!\n", CompTmp);
3561 #endif
3562                                                 }
3563                                         }
3564
3565                                 } else {
3566 #ifdef __MMFILE_TEST_MODE__
3567                                         debug_msg("mmf_file_id3tag_parse_v224: All of the pExtContent Values are NULL\n");
3568 #endif
3569                                 }
3570
3571                         } else {
3572                                 curPos += purelyFramelen;
3573                                 if (purelyFramelen != 0)
3574                                         needToloopv2taglen = MP3_TAGv2_23_TXT_HEADER_LEN;
3575                         }
3576
3577                         if (pExtContent)        _FREE_EX(pExtContent);
3578                         memset(CompTmp, 0, 4);
3579                         if (curPos < taglen) {
3580                                 needToloopv2taglen -= oneFrameLen;
3581                                 v2numOfFrames++;
3582                         } else
3583                                 needToloopv2taglen = MP3_TAGv2_23_TXT_HEADER_LEN;
3584
3585                         oneFrameLen = 0;
3586                         encodingOffSet = 0;
3587                         realCpyFrameNum = 0;
3588                         textEncodingType = 0;
3589                         purelyFramelen = 0;
3590
3591                 }
3592         }
3593
3594         release_characterset_array(charset_array);
3595
3596         if (taglen)
3597                 return true;
3598         else
3599                 return false;
3600
3601 }
3602
3603 EXPORT_API
3604 void mm_file_id3tag_restore_content_info(AvFileContentInfo *pInfo)
3605 {
3606         char    *mpegAudioGenre = NULL/*, *tmpGenreForV1Tag = NULL*/;
3607         bool    bAdditionGenre = false /*, bMpegAudioFrame = false*/;
3608         int     mpegAudioFileLen = 0, idv2IntGenre = 148/*, tmpinx = 0, tmpinx2=0*/;
3609 #ifdef _SM_ONLY
3610         char    *pGenreForUTF16;
3611 #endif
3612         unsigned char genre = pInfo->genre;
3613
3614         /* for Genre Info */
3615         if (pInfo->tagV2Info.bGenreMarked == false) {
3616                 if (pInfo->bV1tagFound == true) {
3617 #ifdef __MMFILE_TEST_MODE__
3618                         debug_msg("Genre: %d\n", genre);
3619 #endif
3620                         if (genre > 147)
3621                                 genre = 148;
3622  
3623                         if (MpegAudio_Genre[genre] != NULL) {
3624                                 pInfo->genreLen = strlen(MpegAudio_Genre[genre]);
3625                                 if (pInfo->genreLen > 0) {
3626                                         /* Give space for NULL character. Hence added "+1" */
3627                                         pInfo->pGenre = mmfile_malloc(sizeof(char) * (pInfo->genreLen + 1));
3628                                         if (pInfo->pGenre) {
3629                                                 strncpy(pInfo->pGenre, MpegAudio_Genre[genre], pInfo->genreLen);
3630                                                 pInfo->pGenre[pInfo->genreLen] = '\0';
3631                                         }
3632                                 }
3633                         }
3634                 } else {
3635 #ifdef __MMFILE_TEST_MODE__
3636                         debug_msg("Genre was not Found.\n");
3637 #endif
3638                 }
3639         } else if (pInfo->tagV2Info.bGenreMarked == true) {
3640                 if (pInfo->genreLen && pInfo->tagV2Info.bGenreUTF16) {
3641                         pInfo->pGenre[pInfo->genreLen + 1] = '\0';
3642                         mpegAudioGenre = mmfile_malloc(sizeof(char) * (pInfo->genreLen * AV_WM_LOCALCODE_SIZE_MAX + 1));
3643 #ifdef _SM_ONLY
3644                         pGenreForUTF16 = (char *)pInfo->pGenre;
3645
3646                         if (WmConvert2LCode(mpegAudioGenre, sizeof(char) * AV_WM_LOCALCODE_SIZE_MAX * (pInfo->genreLen + 1), pGenreForUTF16)) {
3647                                 pInfo->genreLen = strlen(mpegAudioGenre);
3648                                 mpegAudioGenre[pInfo->genreLen] = '\0';
3649                         }
3650 #endif
3651                 } else {
3652 #ifdef __MMFILE_TEST_MODE__
3653                         debug_msg("pInfo->genreLen size is Zero Or not UTF16 code! genreLen[%d] genre[%s]\n", pInfo->genreLen, pInfo->pGenre);
3654 #endif
3655                         if (pInfo->pGenre) {
3656                                 pInfo->genreLen = strlen(pInfo->pGenre);
3657                                 mpegAudioGenre = mmfile_malloc(sizeof(char) * (pInfo->genreLen + 1));
3658                                 if (mpegAudioGenre != NULL) {
3659                                         mpegAudioGenre[pInfo->genreLen] = '\0';
3660                                         strncpy(mpegAudioGenre, pInfo->pGenre, pInfo->genreLen);
3661                                 }
3662                         } else {
3663                                 pInfo->genreLen = 0;
3664                         }
3665                 }
3666
3667                 if (pInfo->pGenre) _FREE_EX(pInfo->pGenre);
3668
3669                 /*tmpinx = 0;*/
3670                 if (mpegAudioGenre != NULL) {
3671                         /**
3672                          *Genre number
3673                          * (XXX)        XXX is 0 - 148
3674                          */
3675                         pInfo->genreLen = strlen(mpegAudioGenre);
3676                         if (pInfo->genreLen >= 3 &&
3677                             mpegAudioGenre[0] == '(' && mpegAudioGenre[pInfo->genreLen - 1] == ')') {
3678                                 bAdditionGenre = true;
3679                                 for (mpegAudioFileLen = 1; mpegAudioFileLen <= pInfo->genreLen - 2; mpegAudioFileLen++) {
3680                                         if (mpegAudioGenre[mpegAudioFileLen] < '0' || mpegAudioGenre[mpegAudioFileLen] > '9') {
3681                                                 bAdditionGenre = false;
3682                                                 break;
3683                                         }
3684                                 }
3685                         }
3686
3687                         if (bAdditionGenre == true) {
3688                                 idv2IntGenre = atoi(mpegAudioGenre + 1);
3689  
3690                                 if (idv2IntGenre > 147 || idv2IntGenre < 0)
3691                                         idv2IntGenre = 148;
3692  
3693                                 if (MpegAudio_Genre[idv2IntGenre] != NULL) {
3694                                         pInfo->genreLen = strlen(MpegAudio_Genre[idv2IntGenre]);
3695                                         if (pInfo->genreLen > 0) {
3696                                                 /* Give space for NULL character. Hence added "+1" */
3697                                                 pInfo->pGenre = mmfile_malloc(sizeof(char) * (pInfo->genreLen + 1));
3698                                                 if (pInfo->pGenre) {
3699                                                         strncpy(pInfo->pGenre, MpegAudio_Genre[idv2IntGenre], pInfo->genreLen);
3700                                                         pInfo->pGenre[pInfo->genreLen] = 0;
3701                                                 }
3702                                         }
3703                                 }
3704 #ifdef __MMFILE_TEST_MODE__
3705                                 debug_msg("pInfo->pGenre = %s\n", pInfo->pGenre);
3706 #endif
3707                         } else if (bAdditionGenre == false && pInfo->genreLen > 0) {
3708                                 /**
3709                                  * Genre string.
3710                                  */
3711
3712                                 /* Give space for NULL character. Hence added "+1" */
3713                                 pInfo->pGenre = mmfile_malloc(sizeof(char) * (pInfo->genreLen + 1));
3714                                 if (pInfo->pGenre) {
3715                                         strncpy(pInfo->pGenre, mpegAudioGenre, pInfo->genreLen);
3716                                         pInfo->pGenre[pInfo->genreLen] = '\0';
3717                                 }
3718 #ifdef __MMFILE_TEST_MODE__
3719                                 debug_msg("pInfo->pGenre = %s, pInfo->genreLen = %d\n", pInfo->pGenre, pInfo->genreLen);
3720 #endif
3721                         } else {
3722 #ifdef __MMFILE_TEST_MODE__
3723                                 debug_msg("Failed to \"(...)\" value to genre = %s\n", pInfo->pGenre);
3724 #endif
3725                         }
3726                 } else {
3727 #ifdef __MMFILE_TEST_MODE__
3728                         debug_msg("mpegAudioGenre = %x\n", mpegAudioGenre);
3729 #endif
3730                 }
3731                 if (mpegAudioGenre)
3732                         _FREE_EX(mpegAudioGenre);
3733
3734         } else {
3735 #ifdef __MMFILE_TEST_MODE__
3736                 debug_msg("Neither ID3 v1 nor v2 info doesn't have Genre Info.\n");
3737 #endif
3738         }
3739
3740 }
3741
3742 void mm_file_free_synclyrics_list(GList *synclyrics_list)
3743 {
3744         int list_len = 0;
3745         int idx = 0;
3746         AvSynclyricsInfo *synclyrics_info = NULL;
3747
3748         if (synclyrics_list == NULL) {
3749                 return;
3750         }
3751
3752         list_len = g_list_length(synclyrics_list);
3753         for (idx = 0; idx < list_len; idx++) {
3754                 synclyrics_info = g_list_nth_data(synclyrics_list, idx);
3755
3756                 free(synclyrics_info->lyric_info);
3757                 synclyrics_info->lyric_info = NULL;
3758
3759                 free(synclyrics_info);
3760                 synclyrics_info = NULL;
3761         }
3762
3763         if (synclyrics_list != NULL) {
3764                 g_list_free(synclyrics_list);
3765                 synclyrics_list = NULL;
3766         }
3767
3768         return;
3769 }
3770