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