support webm format
[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[8] == 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                 long long new_pos = mmfile_tell(fp);
2152
2153                 if ((moov_end == 0) && (new_pos <= basic_header.start_offset)) {
2154                         debug_error(DEBUG, "Wrong position");
2155                         ret = MMFILE_UTIL_FAIL;
2156                         continue;
2157                 }
2158                 basic_header.start_offset = new_pos;
2159
2160         }
2161
2162 exit:
2163         mmfile_close(fp);
2164         return ret;
2165 }
2166
2167 static char *get_string(const char *buf, int buf_size, int *bytes_written)
2168 {
2169         int i = 0, c = 0;
2170         char *q = NULL;
2171         char str[512] = {0, };
2172
2173         q = str;
2174         for (i = 0; i < buf_size; i++) {
2175                 c = buf[i];
2176                 if (c == '\0')
2177                         break;
2178                 if ((q - str) >= (int)sizeof(str) - 1)
2179                         break;
2180                 *q++ = c;
2181         }
2182         *q = '\0';
2183
2184         if (strlen(str) > 0) {
2185                 *bytes_written = strlen(str);
2186                 return strdup(str);
2187         } else {
2188                 *bytes_written = 0;
2189                 return NULL;
2190         }
2191 }
2192
2193 static bool is_numeric(const char *buf, int buf_size)
2194 {
2195         int idx = 0;
2196         bool is_num = true;
2197
2198         for (idx = 0; idx < buf_size; idx++) {
2199                 if (isdigit((int)buf[idx])) {
2200                         continue;
2201                 } else {
2202                         is_num = false;
2203                         break;
2204                 }
2205         }
2206
2207         return is_num;
2208 }
2209
2210 char *rtrimN(char *pStr)
2211 {
2212         int pos = 0;
2213         pos = strlen(pStr) - 1;
2214         for (; pos >= 0; pos--) {
2215                 if (pStr[pos] == 0x20) {
2216                         pStr[pos] = 0x00;
2217                 } else {
2218                         break;
2219                 }
2220         }
2221
2222         return strdup(pStr);
2223 }
2224
2225 bool safe_atoi(char *buffer, int *si)
2226
2227 {
2228         char *end;
2229         errno = 0;
2230
2231         const long sl = strtol(buffer, &end, 10);
2232
2233         if (end == buffer) {
2234                 debug_error(RELEASE, "not a decimal number");
2235                 return FALSE;
2236         } else if ('\0' != *end) {
2237                 debug_error(RELEASE, "extra characters at end of input: %s", end);
2238                 return FALSE;
2239         } else if ((LONG_MIN == sl || LONG_MAX == sl) && (ERANGE == errno)) {
2240                 debug_error(RELEASE, "out of range of type long");
2241                 return FALSE;
2242         } else if (sl > INT_MAX) {
2243                 debug_error(RELEASE, "greater than INT_MAX");
2244                 return FALSE;
2245         } else if (sl < INT_MIN) {
2246                 debug_error(RELEASE, "less than INT_MIN");
2247                 return FALSE;
2248         } else {
2249                 *si = (int)sl;
2250         }
2251         return TRUE;
2252 }
2253
2254 static bool make_characterset_array(char ***charset_array)
2255 {
2256         char *locale = MMFileUtilGetLocale(NULL);
2257
2258         *charset_array = calloc(AV_ID3V2_MAX, sizeof(char *));
2259
2260         if (*charset_array == NULL) {
2261                 debug_error(DEBUG, "calloc failed ");
2262                 if (locale != NULL)
2263                         free(locale);
2264                 return false;
2265         }
2266
2267         if (locale != NULL) {
2268                 (*charset_array)[AV_ID3V2_ISO_8859] = strdup(locale);
2269         } else {
2270                 debug_error(DEBUG, "get locale failed");
2271                 (*charset_array)[AV_ID3V2_ISO_8859] = NULL;
2272         }
2273
2274         (*charset_array)[AV_ID3V2_UTF16] = strdup("UCS2");
2275         (*charset_array)[AV_ID3V2_UTF16_BE] = strdup("UTF16-BE");
2276         (*charset_array)[AV_ID3V2_UTF8] = strdup("UTF-8");
2277
2278         return true;
2279 }
2280
2281 static bool release_characterset_array(char **charset_array)
2282 {
2283         int i = 0;
2284
2285         for (i = 0; i < AV_ID3V2_MAX; i++) {
2286                 if (charset_array[i] != NULL) {
2287                         free(charset_array[i]);
2288                         charset_array[i] = NULL;
2289                 }
2290         }
2291
2292         if (charset_array != NULL) {
2293                 free(charset_array);
2294                 charset_array = NULL;
2295         }
2296
2297         return true;
2298 }
2299
2300 static void init_content_info(AvFileContentInfo *pInfo)
2301 {
2302         pInfo->tagV2Info.bTitleMarked = false;
2303         pInfo->tagV2Info.bArtistMarked = false;
2304         pInfo->tagV2Info.bAlbumMarked = false;
2305         pInfo->tagV2Info.bAlbum_ArtistMarked = false;
2306         pInfo->tagV2Info.bYearMarked = false;
2307         pInfo->tagV2Info.bDescriptionMarked = false;
2308         pInfo->tagV2Info.bGenreMarked = false;
2309         pInfo->tagV2Info.bTrackNumMarked = false;
2310         pInfo->tagV2Info.bEncByMarked = false;
2311         pInfo->tagV2Info.bURLMarked = false;
2312         pInfo->tagV2Info.bCopyRightMarked = false;
2313         pInfo->tagV2Info.bOriginArtistMarked = false;
2314         pInfo->tagV2Info.bComposerMarked = false;
2315         pInfo->tagV2Info.bImageMarked = false;
2316
2317         pInfo->tagV2Info.bRecDateMarked = false;
2318         pInfo->tagV2Info.bContentGroupMarked = false;
2319
2320         pInfo->tagV2Info.bUnsyncLyricsMarked = false;
2321         pInfo->tagV2Info.bSyncLyricsMarked = false;
2322         pInfo->tagV2Info.bConductorMarked = false;
2323         pInfo->tagV2Info.bGenreUTF16 = false;
2324
2325         pInfo->imageInfo.bURLInfo = false;
2326         pInfo->imageInfo.pImageBuf = NULL;
2327         pInfo->imageInfo.imageLen = 0;
2328 }
2329
2330 EXPORT_API
2331 bool mm_file_id3tag_parse_v110(AvFileContentInfo *pInfo,  unsigned char *buffer)
2332 {
2333         const char *locale = MMFileUtilGetLocale(NULL);
2334         char *pFullStr = NULL;
2335
2336         debug_msg(RELEASE, "ID3tag v110--------------------------------------------------------------\n");
2337
2338         if (pInfo->tagV2Info.bTitleMarked == false) {
2339                 pFullStr = mmfile_string_convert((const char *)&buffer[3], MP3_ID3_TITLE_LENGTH, "UTF-8", locale, NULL, (unsigned int *)&pInfo->titleLen);
2340                 if (pFullStr != NULL) {
2341                         pInfo->pTitle = rtrimN(pFullStr);
2342                         free(pFullStr);
2343                 }
2344
2345                 debug_msg(RELEASE, "pInfo->pTitle returned =(%s), pInfo->titleLen(%d)\n", pInfo->pTitle, pInfo->titleLen);
2346         }
2347
2348         if (pInfo->tagV2Info.bArtistMarked == false) {
2349                 pFullStr = mmfile_string_convert((const char *)&buffer[33], MP3_ID3_ARTIST_LENGTH, "UTF-8", locale, NULL, (unsigned int *)&pInfo->artistLen);
2350                 if (pFullStr != NULL) {
2351                         pInfo->pArtist = rtrimN(pFullStr);
2352                         free(pFullStr);
2353                 }
2354
2355                 debug_msg(RELEASE, "pInfo->pArtist returned =(%s), pInfo->artistLen(%d)\n", pInfo->pArtist, pInfo->artistLen);
2356         }
2357
2358         if (pInfo->tagV2Info.bAlbumMarked == false) {
2359                 pFullStr = mmfile_string_convert((const char *)&buffer[63], MP3_ID3_ALBUM_LENGTH, "UTF-8", locale, NULL, (unsigned int *)&pInfo->albumLen);
2360                 if (pFullStr != NULL) {
2361                         pInfo->pAlbum = rtrimN(pFullStr);
2362                         free(pFullStr);
2363                 }
2364
2365                 debug_msg(RELEASE, "pInfo->pAlbum returned =(%s), pInfo->albumLen(%d)\n", pInfo->pAlbum, pInfo->albumLen);
2366         }
2367
2368         if (pInfo->tagV2Info.bYearMarked == false) {
2369
2370                 pInfo->pYear = mmfile_string_convert((const char *)&buffer[93], MP3_ID3_YEAR_LENGTH, "UTF-8", locale, NULL, (unsigned int *)&pInfo->yearLen);
2371
2372                 debug_msg(RELEASE, "pInfo->pYear returned =(%s), pInfo->yearLen(%d)\n", pInfo->pYear, pInfo->yearLen);
2373
2374                 if (pInfo->pYear == NULL) {     /*Use same logic with ffmpeg*/
2375                         pInfo->pYear = get_string((const char *)&buffer[93], MP3_ID3_YEAR_LENGTH, (int *)&pInfo->yearLen);
2376                         debug_msg(RELEASE, "pInfo->pYear returned =(%s), pInfo->yearLen(%d)\n", pInfo->pYear, pInfo->yearLen);
2377                 }
2378         }
2379
2380         if (pInfo->tagV2Info.bDescriptionMarked == false) {
2381                 pInfo->pComment = mmfile_string_convert((const char *)&buffer[97], MP3_ID3_DESCRIPTION_LENGTH, "UTF-8", locale, NULL, (unsigned int *)&pInfo->commentLen);
2382                 debug_msg(RELEASE, "pInfo->pComment returned =(%s), pInfo->commentLen(%d)\n", pInfo->pComment, pInfo->commentLen);
2383
2384                 if (pInfo->pComment == NULL) {  /*Use same logic with ffmpeg*/
2385                         pInfo->pComment = get_string((const char *)&buffer[97], MP3_ID3_DESCRIPTION_LENGTH, (int *)&pInfo->commentLen);
2386                         debug_msg(RELEASE, "pInfo->pComment returned =(%s), pInfo->commentLen(%d)\n", pInfo->pComment, pInfo->commentLen);
2387                 }
2388         }
2389
2390         if (pInfo->tagV2Info.bTrackNumMarked == false) {
2391                 pInfo->pTrackNum = mmfile_malloc(5);
2392                 if (pInfo->pTrackNum != NULL) {
2393                         pInfo->pTrackNum[4] = 0;
2394                         snprintf(pInfo->pTrackNum, 4, "%04d", (int)buffer[126]);
2395                         pInfo->tracknumLen = strlen(pInfo->pTrackNum);
2396
2397                         debug_msg(RELEASE, "pInfo->pTrackNum returned =(%s), pInfo->tracknumLen(%d)\n", pInfo->pTrackNum, pInfo->tracknumLen);
2398                 }
2399         }
2400
2401         if (pInfo->tagV2Info.bGenreMarked == false) {
2402                 pInfo->genre = buffer[127];
2403                 debug_msg(RELEASE, "pInfo->genre returned genre number (%d)\n", pInfo->genre);
2404         }
2405
2406         return true;
2407 }
2408
2409 EXPORT_API
2410 bool mm_file_id3tag_parse_v222(AvFileContentInfo *pInfo, unsigned char *buffer)
2411 {
2412         unsigned long taglen = 0;
2413         unsigned long needToloopv2taglen;
2414         unsigned long oneFrameLen = 0;
2415         unsigned long v2numOfFrames = 0;
2416         unsigned long curPos = 0;
2417         char CompTmp[4];
2418         unsigned char *pExtContent = NULL;
2419         unsigned long purelyFramelen = 0;
2420         unsigned int encodingOffSet = 0;
2421         int inx = 0, realCpyFrameNum = 0,
2422             /*checkImgMimeTypeMax = 0, */checkImgExtMax = 0,
2423             imgstartOffset = 0, tmp = 0;
2424
2425         int textEncodingType = 0;
2426
2427         char **charset_array = NULL;
2428
2429         make_characterset_array(&charset_array);
2430
2431         init_content_info(pInfo);
2432
2433         taglen = pInfo->tagV2Info.tagLen;
2434         needToloopv2taglen = taglen - MP3_TAGv2_HEADER_LEN;
2435         curPos = MP3_TAGv2_HEADER_LEN;
2436
2437         debug_msg(RELEASE, "ID3tag v222--------------------------------------------------------------\n");
2438
2439         if (needToloopv2taglen - MP3_TAGv2_22_TXT_HEADER_LEN > MP3_TAGv2_22_TXT_HEADER_LEN) {
2440                 v2numOfFrames = 1;
2441                 while (needToloopv2taglen > MP3_TAGv2_22_TXT_HEADER_LEN) {
2442                         if ((buffer[curPos] < '0' || buffer[curPos] > 'Z') || (buffer[curPos + 1] < '0' || buffer[curPos + 1] > 'Z')
2443                             || (buffer[curPos + 2] < '0' || buffer[curPos + 2] > 'Z'))
2444                                 break;
2445
2446                         memcpy(CompTmp, &buffer[curPos], 3);
2447
2448                         CompTmp[3] = 0;
2449                         oneFrameLen = MP3_TAGv2_22_TXT_HEADER_LEN;
2450                         oneFrameLen += (unsigned long)buffer[3 + curPos] << 16 | (unsigned long)buffer[4 + curPos] << 8
2451                                                 | (unsigned long)buffer[5 + curPos];
2452                         if (oneFrameLen > taglen - curPos)
2453                                 break;
2454                         purelyFramelen = oneFrameLen - MP3_TAGv2_22_TXT_HEADER_LEN;
2455                         curPos += MP3_TAGv2_22_TXT_HEADER_LEN;
2456
2457                         if (oneFrameLen > MP3_TAGv2_22_TXT_HEADER_LEN && purelyFramelen <= taglen - curPos) {
2458                                 curPos += purelyFramelen;
2459
2460                                 if (buffer[curPos - purelyFramelen] == 0x00) {
2461                                         encodingOffSet = 1;
2462                                         textEncodingType = AV_ID3V2_ISO_8859;
2463                                 } else if (buffer[curPos - purelyFramelen] == 0x01) {
2464                                         encodingOffSet = 1;
2465                                         textEncodingType = AV_ID3V2_UTF16;
2466                                 }
2467
2468                                 /*in order to deliver valid string to MP */
2469                                 while ((buffer[curPos - purelyFramelen + encodingOffSet] < 0x20) && (encodingOffSet < purelyFramelen))
2470                                         encodingOffSet++;
2471
2472                                 if (encodingOffSet < purelyFramelen) {
2473                                         realCpyFrameNum = purelyFramelen - encodingOffSet;
2474                                         pExtContent = mmfile_malloc(realCpyFrameNum + 3);
2475
2476                                         if (pExtContent == NULL) {
2477                                                 debug_error(DEBUG, "out of memory for pExtContent\n");
2478                                                 continue;
2479                                         }
2480
2481                                         memset(pExtContent, '\0', realCpyFrameNum + 3);
2482
2483                                         memcpy(pExtContent, &buffer[curPos - purelyFramelen + encodingOffSet], purelyFramelen - encodingOffSet);
2484
2485                                         if (realCpyFrameNum > 0) {
2486                                                 if (strncmp((char *)CompTmp, "TT2", 3) == 0 && pInfo->tagV2Info.bTitleMarked == false) {
2487                                                         pInfo->pTitle = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->titleLen);
2488                                                         debug_msg(RELEASE, "pInfo->pTitle returned = (%s), pInfo->titleLen(%d)\n", pInfo->pTitle, pInfo->titleLen);
2489                                                         pInfo->tagV2Info.bTitleMarked = true;
2490                                                 } else if (strncmp((char *)CompTmp, "TP1", 3) == 0 && pInfo->tagV2Info.bArtistMarked == false) {
2491                                                         pInfo->pArtist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->artistLen);
2492                                                         debug_msg(RELEASE, "pInfo->pArtist returned = (%s), pInfo->artistLen(%d)\n", pInfo->pArtist, pInfo->artistLen);
2493                                                         pInfo->tagV2Info.bArtistMarked = true;
2494                                                 } else if (strncmp((char *)CompTmp, "TP2", 3) == 0 && pInfo->tagV2Info.bAlbum_ArtistMarked == false) {
2495                                                         pInfo->pAlbum_Artist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->album_artistLen);
2496                                                         debug_msg(RELEASE, "pInfo->pAlbum_Artist returned = (%s), pInfo->album_artistLen(%d)\n", pInfo->pAlbum_Artist, pInfo->album_artistLen);
2497                                                         pInfo->tagV2Info.bAlbum_ArtistMarked = true;
2498                                                 } else if (strncmp((char *)CompTmp, "TP3", 3) == 0 && pInfo->tagV2Info.bConductorMarked == false) {
2499                                                         pInfo->pConductor = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->conductorLen);
2500                                                         debug_msg(RELEASE, "pInfo->pConductor returned = (%s), pInfo->conductorLen(%d)\n", pInfo->pConductor, pInfo->conductorLen);
2501                                                         pInfo->tagV2Info.bConductorMarked = true;
2502                                                 } else if (strncmp((char *)CompTmp, "TAL", 3) == 0 && pInfo->tagV2Info.bAlbumMarked == false) {
2503                                                         pInfo->pAlbum = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->albumLen);
2504                                                         debug_msg(RELEASE, "pInfo->pAlbum returned = (%s), pInfo->albumLen(%d)\n", pInfo->pAlbum, pInfo->albumLen);
2505                                                         pInfo->tagV2Info.bAlbumMarked = true;
2506                                                 } else if (strncmp((char *)CompTmp, "TYE", 3) == 0 && pInfo->tagV2Info.bYearMarked == false) {
2507                                                         pInfo->pYear = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->yearLen);
2508                                                         debug_msg(RELEASE, "pInfo->pYear returned = (%s), pInfo->yearLen(%d)\n", pInfo->pYear, pInfo->yearLen);
2509                                                         pInfo->tagV2Info.bYearMarked = true;
2510                                                 } else if (strncmp((char *)CompTmp, "COM", 3) == 0 && pInfo->tagV2Info.bDescriptionMarked == false) {
2511                                                         /*skip language data! */
2512                                                         if (realCpyFrameNum > 4) {
2513                                                                 realCpyFrameNum -= 4;
2514                                                                 tmp = 4;
2515
2516                                                                 /*pExtContent[tmp+1] value should't have encoding value */
2517                                                                 if (pExtContent[tmp] > 0x20 && (pExtContent[tmp - 1] == 0x00 || pExtContent[tmp - 1] == 0x01)) {
2518                                                                         if (pExtContent[tmp - 1] == 0x00)
2519                                                                                 textEncodingType = AV_ID3V2_ISO_8859;
2520                                                                         else
2521                                                                                 textEncodingType = AV_ID3V2_UTF16;
2522
2523                                                                         pInfo->pComment = mmfile_string_convert((char *)&pExtContent[tmp], realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->commentLen);
2524                                                                         debug_msg(RELEASE, "pInfo->pComment returned = (%s), pInfo->commentLen(%d)\n", pInfo->pComment, pInfo->commentLen);
2525                                                                         pInfo->tagV2Info.bDescriptionMarked = true;
2526                                                                 } else {
2527                                                                         debug_msg(RELEASE, "mmf_file_id3tag_parse_v222: failed to get Comment Info tmp(%d), purelyFramelen - encodingOffSet(%lu)\n", tmp, purelyFramelen - encodingOffSet);
2528                                                                 }
2529                                                         } else {
2530                                                                 debug_msg(RELEASE, "mmf_file_id3tag_parse_v222: Description info too small to parse realCpyFrameNum(%d)\n", realCpyFrameNum);
2531                                                         }
2532                                                         tmp = 0;
2533
2534                                                 } else if (strncmp((char *)CompTmp, "TCO", 3) == 0 && pInfo->tagV2Info.bGenreMarked == false) {
2535                                                         pInfo->pGenre = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->genreLen);
2536                                                         debug_msg(RELEASE, "pInfo->pGenre returned = (%s), pInfo->genreLen(%d)\n", pInfo->pGenre, pInfo->genreLen);
2537
2538                                                         if ((pInfo->pGenre != NULL) && (pInfo->genreLen > 0)) {
2539                                                                 bool ret = FALSE;
2540                                                                 int int_genre = -1;
2541
2542                                                                 ret = is_numeric(pInfo->pGenre, pInfo->genreLen);
2543
2544                                                                 if (ret == TRUE) {
2545                                                                         ret = safe_atoi(pInfo->pGenre, &int_genre);
2546                                                                         if (ret == TRUE) {
2547                                                                                 debug_msg(RELEASE, "genre information is inteager [%d]\n", int_genre);
2548
2549                                                                                 /*Change int to string */
2550                                                                                 if ((0 <= int_genre) && (int_genre < GENRE_COUNT - 1)) {
2551                                                                                         /*save genreinfo like "(123)". mm_file_id3tag_restore_content_info convert it to string*/
2552                                                                                         char tmp_genre[6] = {0, };      /*ex. "(123)+NULL"*/
2553                                                                                         int tmp_genre_len = 0;
2554
2555                                                                                         memset(tmp_genre, 0, 6);
2556                                                                                         snprintf(tmp_genre, sizeof(tmp_genre), "(%d)", int_genre);
2557
2558                                                                                         tmp_genre_len = strlen(tmp_genre);
2559                                                                                         if (tmp_genre_len > 0) {
2560                                                                                                 if (pInfo->pGenre) _FREE_EX(pInfo->pGenre);
2561                                                                                                 pInfo->pGenre = mmfile_malloc(sizeof(char) * (tmp_genre_len + 1));
2562                                                                                                 if (pInfo->pGenre) {
2563                                                                                                         SAFE_STRLCPY(pInfo->pGenre, tmp_genre, tmp_genre_len + 1);
2564                                                                                                 }
2565                                                                                         }
2566                                                                                 }
2567                                                                         } else {
2568                                                                                 debug_error(RELEASE, "genre information is wrong inteager [%s]\n", pInfo->pGenre);
2569                                                                         }
2570                                                                 }
2571                                                         }
2572
2573                                                         pInfo->tagV2Info.bGenreMarked = true;
2574                                                 } else if (strncmp((char *)CompTmp, "TRK", 3) == 0 && pInfo->tagV2Info.bTrackNumMarked == false) {
2575                                                         pInfo->pTrackNum = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->tracknumLen);
2576                                                         debug_msg(RELEASE, "pInfo->pTrackNum returned = (%s), pInfo->tracknumLen(%d)\n", pInfo->pTrackNum, pInfo->tracknumLen);
2577                                                         pInfo->tagV2Info.bTrackNumMarked = true;
2578                                                 } else if (strncmp((char *)CompTmp, "TEN", 3) == 0 && pInfo->tagV2Info.bEncByMarked == false) {
2579                                                         pInfo->pEncBy = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->encbyLen);
2580                                                         debug_msg(RELEASE, "pInfo->pEncBy returned = (%s), pInfo->encbyLen(%d)\n", pInfo->pEncBy, pInfo->encbyLen);
2581                                                         pInfo->tagV2Info.bEncByMarked = true;
2582                                                 } else if (strncmp((char *)CompTmp, "WXX", 3) == 0 && pInfo->tagV2Info.bURLMarked == false) {
2583                                                         if (realCpyFrameNum > 4) {
2584                                                                 /*skip language data! */
2585                                                                 realCpyFrameNum -= 4;
2586                                                                 tmp = 4;
2587
2588                                                                 /*pExtContent[tmp+1] value should't have null value */
2589                                                                 if (pExtContent[tmp] > 0x20 && (pExtContent[tmp - 1] == 0x00 || pExtContent[tmp - 1] == 0x01)) {
2590                                                                         if (pExtContent[tmp - 1] == 0x00)
2591                                                                                 textEncodingType = AV_ID3V2_ISO_8859;
2592                                                                         else
2593                                                                                 textEncodingType = AV_ID3V2_UTF16;
2594
2595                                                                         pInfo->pURL = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->urlLen);
2596                                                                         debug_msg(RELEASE, "pInfo->pURL returned = (%s), pInfo->urlLen(%d)\n", pInfo->pURL, pInfo->urlLen);
2597                                                                         pInfo->tagV2Info.bURLMarked = true;
2598                                                                 } else {
2599                                                                         debug_msg(RELEASE, "mmf_file_id3tag_parse_v222: failed to get URL Info tmp(%d), purelyFramelen - encodingOffSet(%lu)\n", tmp, purelyFramelen - encodingOffSet);
2600                                                                 }
2601                                                         } else {
2602                                                                 debug_msg(RELEASE, "mmf_file_id3tag_parse_v222: URL info too small to parse realCpyFrameNum(%d)\n", realCpyFrameNum);
2603                                                         }
2604                                                         tmp = 0;
2605                                                 } else if (strncmp((char *)CompTmp, "TCR", 3) == 0 && pInfo->tagV2Info.bCopyRightMarked == false) {
2606                                                         pInfo->pCopyright = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->copyrightLen);
2607                                                         debug_msg(RELEASE, "pInfo->pCopyright returned = (%s), pInfo->copyrightLen(%d)\n", pInfo->pCopyright, pInfo->copyrightLen);
2608                                                         pInfo->tagV2Info.bCopyRightMarked = true;
2609                                                 } else if (strncmp((char *)CompTmp, "TOA", 3) == 0 && pInfo->tagV2Info.bOriginArtistMarked == false) {
2610                                                         pInfo->pOriginArtist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->originartistLen);
2611                                                         debug_msg(RELEASE, "pInfo->pOriginArtist returned = (%s), pInfo->originartistLen(%d)\n", pInfo->pOriginArtist, pInfo->originartistLen);
2612                                                         pInfo->tagV2Info.bOriginArtistMarked = true;
2613                                                 } else if (strncmp((char *)CompTmp, "TCM", 3) == 0 && pInfo->tagV2Info.bComposerMarked == false) {
2614                                                         pInfo->pComposer = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->composerLen);
2615                                                         debug_msg(RELEASE, "pInfo->pComposer returned = (%s), pInfo->originartistLen(%d)\n", pInfo->pComposer, pInfo->composerLen);
2616                                                         pInfo->tagV2Info.bComposerMarked = true;
2617                                                 } else if (strncmp((char *)CompTmp, "TRD", 3) == 0 && pInfo->tagV2Info.bRecDateMarked == false) {
2618                                                         pInfo->pRecDate = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->recdateLen);
2619                                                         debug_msg(RELEASE, "pInfo->pRecDate returned = (%s), pInfo->recdateLen(%d)\n", pInfo->pRecDate, pInfo->recdateLen);
2620                                                         pInfo->tagV2Info.bRecDateMarked = true;
2621                                                 } else if (strncmp((char *)CompTmp, "PIC", 3) == 0 && pInfo->tagV2Info.bImageMarked == false && realCpyFrameNum <= 2000000) {
2622                                                         if (pExtContent[0] != 0) {
2623                                                                 for (inx = 0; inx < MP3_ID3_IMAGE_EXT_MAX_LENGTH; inx++)
2624                                                                         pInfo->imageInfo.imageExt[inx] = '\0';/*ini mimetype variable */
2625
2626                                                                 while ((checkImgExtMax < MP3_ID3_IMAGE_EXT_MAX_LENGTH - 1) && pExtContent[checkImgExtMax] != '\0') {
2627                                                                         pInfo->imageInfo.imageExt[checkImgExtMax] = pExtContent[checkImgExtMax];
2628                                                                         checkImgExtMax++;
2629                                                                 }
2630                                                         } else {
2631                                                                 debug_msg(RELEASE, "mmf_file_id3tag_parse_v222: PIC image's not included to image Extention\n");
2632                                                         }
2633
2634                                                         imgstartOffset += checkImgExtMax;
2635
2636                                                         if (pExtContent[imgstartOffset] < AV_ID3V2_PICTURE_TYPE_MAX) {
2637                                                                 pInfo->imageInfo.pictureType = pExtContent[imgstartOffset];
2638                                                         }
2639                                                         imgstartOffset++;/*PictureType(1byte) */
2640
2641                                                         if (pExtContent[imgstartOffset] != 0x0) {
2642                                                                 int cur_pos = 0;
2643                                                                 int dis_len = 0;
2644                                                                 int new_dis_len = 0;
2645                                                                 char *tmp_desc = NULL;
2646
2647                                                                 while (1) {
2648                                                                         if (pExtContent[imgstartOffset + cur_pos] == '\0') {
2649                                                                                 if (realCpyFrameNum < imgstartOffset + cur_pos) {
2650                                                                                         debug_error(DEBUG, "End of APIC Tag %d %d %d\n", realCpyFrameNum, imgstartOffset, cur_pos);
2651                                                                                         break;
2652                                                                                 }
2653                                                                                 /*check end of image description*/
2654                                                                                 if ((pExtContent[imgstartOffset + cur_pos + 1] == gTagJPEGHeader[0]) ||
2655                                                                                     (pExtContent[imgstartOffset + cur_pos + 1] == gTagPNGHeader[0])) {
2656                                                                                         debug_msg(RELEASE, "length of description (%d)", cur_pos);
2657                                                                                         break;
2658                                                                                 }
2659                                                                         }
2660                                                                         cur_pos++;
2661                                                                 }
2662
2663                                                                 dis_len = cur_pos + 1;
2664
2665                                                                 tmp_desc = mmfile_malloc(sizeof(char) * dis_len);
2666
2667                                                                 if (tmp_desc != NULL) {
2668                                                                         memcpy(tmp_desc, pExtContent + imgstartOffset, dis_len);
2669
2670                                                                         /*convert description*/
2671                                                                         pInfo->imageInfo.imageDescription = mmfile_string_convert(tmp_desc, dis_len, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&new_dis_len);
2672                                                                         mmfile_free(tmp_desc);
2673                                                                         debug_msg(RELEASE, "new_desc %s(%d)\n", pInfo->imageInfo.imageDescription, new_dis_len);
2674                                                                         pInfo->imageInfo.imgDesLen = new_dis_len; /**/
2675                                                                 }
2676
2677                                                                 imgstartOffset += cur_pos;
2678                                                         } else {
2679                                                                 pInfo->imageInfo.imgDesLen = 0;
2680                                                         }
2681
2682                                                         if ((pExtContent[imgstartOffset] == '\0') && (realCpyFrameNum - imgstartOffset > 0)) {
2683                                                                 imgstartOffset++; /* endofDesceriptionType(1byte) */
2684
2685                                                                 while (pExtContent[imgstartOffset] == '\0') {   /*some content has useless '\0' in front of picture data */
2686                                                                         imgstartOffset++;
2687                                                                 }
2688
2689                                                                 debug_msg(RELEASE, "after scaning imgDescription imgstartOffset(%d) value!\n", imgstartOffset);
2690
2691                                                                 if (realCpyFrameNum - imgstartOffset > 0) {
2692                                                                         pInfo->imageInfo.imageLen = realCpyFrameNum - imgstartOffset;
2693                                                                         pInfo->imageInfo.pImageBuf = mmfile_malloc(pInfo->imageInfo.imageLen + 1);
2694
2695                                                                         if (pInfo->imageInfo.pImageBuf != NULL) {
2696                                                                                 memcpy(pInfo->imageInfo.pImageBuf, pExtContent + imgstartOffset, pInfo->imageInfo.imageLen);
2697                                                                                 pInfo->imageInfo.pImageBuf[pInfo->imageInfo.imageLen] = 0;
2698                                                                         }
2699
2700                                                                         if (IS_INCLUDE_URL(pInfo->imageInfo.imageMIMEType))
2701                                                                                 pInfo->imageInfo.bURLInfo = true; /*if mimetype is "-->", image date has an URL */
2702                                                                 } else {
2703                                                                         debug_msg(RELEASE, "No APIC image!! realCpyFrameNum(%d) - imgstartOffset(%d)\n", realCpyFrameNum, imgstartOffset);
2704                                                                 }
2705                                                         }
2706
2707                                                         /*checkImgMimeTypeMax = 0;*/
2708                                                         checkImgExtMax = 0;
2709                                                         inx = 0;
2710                                                         imgstartOffset = 0;
2711                                                         pInfo->tagV2Info.bImageMarked = true;
2712
2713                                                 }
2714                                         }
2715
2716                                 }
2717                         } else {
2718                                 curPos += purelyFramelen;
2719                                 if (purelyFramelen != 0)
2720                                         needToloopv2taglen = MP3_TAGv2_22_TXT_HEADER_LEN;
2721                         }
2722
2723                         if (pExtContent)        _FREE_EX(pExtContent);
2724                         memset(CompTmp, 0, 4);
2725                         if (curPos < taglen) {
2726                                 needToloopv2taglen -= oneFrameLen;
2727                                 v2numOfFrames++;
2728                         } else
2729                                 needToloopv2taglen = MP3_TAGv2_22_TXT_HEADER_LEN;
2730                         oneFrameLen = 0;
2731                         encodingOffSet = 0;
2732                         realCpyFrameNum = 0;
2733                         textEncodingType = 0;
2734                         purelyFramelen = 0;
2735
2736                 }
2737         }
2738
2739         release_characterset_array(charset_array);
2740
2741         if (taglen) {
2742                 return true;
2743         } else {
2744                 return false;
2745         }
2746 }
2747
2748 EXPORT_API
2749 bool mm_file_id3tag_parse_v223(AvFileContentInfo *pInfo, unsigned char *buffer)
2750 {
2751         unsigned long taglen = 0;
2752         unsigned long needToloopv2taglen;
2753         unsigned long oneFrameLen = 0;
2754         unsigned long v2numOfFrames = 0;
2755         unsigned long curPos = 0;
2756         char CompTmp[5];
2757         unsigned char *pExtContent = NULL;
2758         unsigned long purelyFramelen = 0;
2759         unsigned int encodingOffSet = 0;
2760         int inx = 0, realCpyFrameNum = 0, checkImgMimeTypeMax = 0, imgstartOffset = 0,  tmp = 0;
2761         unsigned int textEncodingType = 0;
2762         char **charset_array = NULL;
2763         const char *MIME_PRFIX = "image/";
2764
2765         make_characterset_array(&charset_array);
2766
2767         init_content_info(pInfo);
2768
2769         taglen = pInfo->tagV2Info.tagLen;
2770         needToloopv2taglen = taglen - MP3_TAGv2_HEADER_LEN;
2771         curPos = MP3_TAGv2_HEADER_LEN;
2772
2773         debug_msg(RELEASE, "ID3tag v223--------------------------------------------------------------\n");
2774
2775         /* check Extended Header */
2776         if (buffer[5] & 0x40) {
2777                 /* if extended header exists, skip it*/
2778                 int extendedHeaderLen = (unsigned long)buffer[10] << 21 | (unsigned long)buffer[11] << 14 | (unsigned long)buffer[12] << 7  | (unsigned long)buffer[13];
2779
2780                 debug_msg(RELEASE, "--------------- extendedHeaderLen = %d\n", extendedHeaderLen);
2781
2782                 if (extendedHeaderLen > (int)(taglen - curPos)) {
2783                         debug_error(DEBUG, "extended header too long.\n");
2784                 } else {
2785                         curPos += extendedHeaderLen;
2786                         curPos += 4;
2787                 }
2788         }
2789
2790         if (needToloopv2taglen - MP3_TAGv2_23_TXT_HEADER_LEN > MP3_TAGv2_23_TXT_HEADER_LEN) {
2791                 v2numOfFrames = 1;
2792                 while (needToloopv2taglen > MP3_TAGv2_23_TXT_HEADER_LEN) {
2793                         if ((buffer[curPos] < '0' || buffer[curPos] > 'Z') || (buffer[curPos + 1] < '0' || buffer[curPos + 1] > 'Z')
2794                             || (buffer[curPos + 2] < '0' || buffer[curPos + 2] > 'Z') || (buffer[curPos + 3] < '0' || buffer[curPos + 3] > 'Z'))
2795                                 break;
2796
2797                         memcpy(CompTmp, &buffer[curPos], 4);
2798
2799                         CompTmp[4] = 0;
2800                         oneFrameLen = MP3_TAGv2_23_TXT_HEADER_LEN;
2801                         oneFrameLen += (unsigned long)buffer[4 + curPos] << 24 | (unsigned long)buffer[5 + curPos] << 16
2802                                                 | (unsigned long)buffer[6 + curPos] << 8 | (unsigned long)buffer[7 + curPos];
2803
2804                         debug_msg(RELEASE, "----------------------------------------------------------------------------------------------------\n");
2805
2806                         if (oneFrameLen > taglen - curPos)
2807                                 break;
2808
2809                         purelyFramelen = oneFrameLen - MP3_TAGv2_23_TXT_HEADER_LEN;
2810                         curPos += MP3_TAGv2_23_TXT_HEADER_LEN;
2811
2812                         if (oneFrameLen > MP3_TAGv2_23_TXT_HEADER_LEN && purelyFramelen <= taglen - curPos) {
2813                                 curPos += purelyFramelen;
2814
2815                                 if (IS_ENCODEDBY_UTF16(buffer + (curPos - purelyFramelen))) {
2816                                         encodingOffSet = 2;
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))) {
2820                                         encodingOffSet = 2;
2821                                         debug_msg(RELEASE, "this text string(%s) encoded by UTF16 encodingOffSet(%d)\n", CompTmp, encodingOffSet);
2822                                         textEncodingType = AV_ID3V2_UTF16_BE;
2823                                 } else if (IS_ENCODEDBY_UTF16(buffer + (curPos - purelyFramelen + 1))) {
2824                                         encodingOffSet = 3;
2825                                         debug_msg(RELEASE, "this text string(%s) encoded by UTF16 encodingOffSet(%d)\n", CompTmp, encodingOffSet);
2826                                         textEncodingType = AV_ID3V2_UTF16;
2827                                 } else if (IS_ENCODEDBY_UTF16_R(buffer + (curPos - purelyFramelen + 1))) {
2828                                         encodingOffSet = 3;
2829                                         debug_msg(RELEASE, "this text string(%s) encoded by UTF16 encodingOffSet(%d)\n", CompTmp, encodingOffSet);
2830                                         textEncodingType = AV_ID3V2_UTF16_BE;
2831                                 } else {
2832                                         if (buffer[curPos - purelyFramelen + encodingOffSet] == 0x00) {
2833                                                 debug_msg(RELEASE, "encodingOffset will be set to 1\n");
2834                                                 encodingOffSet = 1;
2835                                         } else {
2836                                                 debug_msg(RELEASE, "Finding encodingOffset\n");
2837
2838                                                 while ((buffer[curPos - purelyFramelen + encodingOffSet] < 0x20) && (encodingOffSet < purelyFramelen)) /* text string encoded by ISO-8859-1 */
2839                                                         encodingOffSet++;
2840                                         }
2841                                         textEncodingType = AV_ID3V2_ISO_8859;
2842                                         debug_msg(RELEASE, "this text string(%s) encoded by ISO-8859-1 encodingOffSet(%d)\n", CompTmp, encodingOffSet);
2843                                 }
2844
2845                                 if (pExtContent)        _FREE_EX(pExtContent);
2846
2847                                 if (encodingOffSet < purelyFramelen) {
2848                                         realCpyFrameNum = purelyFramelen - encodingOffSet;
2849                                         pExtContent = mmfile_malloc(realCpyFrameNum + 3);
2850
2851                                         if (pExtContent == NULL) {
2852                                                 debug_msg(DEBUG, "pExtContent malloc failed\n");
2853                                                 continue;
2854                                         }
2855
2856                                         memset(pExtContent, '\0', realCpyFrameNum + 3);
2857
2858                                         if (textEncodingType != AV_ID3V2_UTF16 && textEncodingType != AV_ID3V2_UTF16_BE) {
2859                                                 if (CompTmp[0] == 'T' || (strcmp(CompTmp, "APIC") == 0)) {
2860                                                         debug_msg(RELEASE, "get the new text ecoding type\n");
2861                                                         textEncodingType = buffer[curPos - purelyFramelen + encodingOffSet - 1];
2862                                                 }
2863                                         }
2864
2865                                         if (textEncodingType > AV_ID3V2_MAX) {
2866                                                 debug_msg(DEBUG, "WRONG ENCOIDNG TYPE [%d], FRAME[%s]\n", textEncodingType, (char *)CompTmp);
2867                                                 continue;
2868                                         }
2869
2870                                         memcpy(pExtContent, &buffer[curPos - purelyFramelen + encodingOffSet], purelyFramelen - encodingOffSet);
2871                                         if (realCpyFrameNum > 0) {
2872                                                 if (strncmp((char *)CompTmp, "TIT2", 4) == 0 && pInfo->tagV2Info.bTitleMarked == false) {
2873                                                         pInfo->pTitle = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->titleLen);
2874                                                         debug_msg(RELEASE, "pInfo->pTitle returned = (%s), pInfo->titleLen(%d)\n", pInfo->pTitle, pInfo->titleLen);
2875                                                         pInfo->tagV2Info.bTitleMarked = true;
2876
2877                                                 } else if (strncmp((char *)CompTmp, "TPE1", 4) == 0 && pInfo->tagV2Info.bArtistMarked == false) {
2878                                                         pInfo->pArtist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->artistLen);
2879                                                         debug_msg(RELEASE, "pInfo->pArtist returned = (%s), pInfo->artistLen(%d)\n", pInfo->pArtist, pInfo->artistLen);
2880                                                         pInfo->tagV2Info.bArtistMarked = true;
2881                                                 } else if (strncmp((char *)CompTmp, "TPE2", 4) == 0 && pInfo->tagV2Info.bAlbum_ArtistMarked == false) {
2882                                                         pInfo->pAlbum_Artist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->album_artistLen);
2883                                                         debug_msg(RELEASE, "pInfo->pAlbum_Artist returned = (%s), pInfo->album_artistLen(%d)\n", pInfo->pAlbum_Artist, pInfo->album_artistLen);
2884                                                         pInfo->tagV2Info.bAlbum_ArtistMarked = true;
2885                                                 } else if (strncmp((char *)CompTmp, "TPE3", 4) == 0 && pInfo->tagV2Info.bConductorMarked == false) {
2886                                                         pInfo->pConductor = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->conductorLen);
2887                                                         debug_msg(RELEASE, "pInfo->pConductor returned = (%s), pInfo->conductorLen(%d)\n", pInfo->pConductor, pInfo->conductorLen);
2888                                                         pInfo->tagV2Info.bConductorMarked = true;
2889                                                 } else if (strncmp((char *)CompTmp, "TALB", 4) == 0 && pInfo->tagV2Info.bAlbumMarked == false) {
2890                                                         pInfo->pAlbum = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->albumLen);
2891                                                         debug_msg(RELEASE, "pInfo->pAlbum returned = (%s), pInfo->albumLen(%d)\n", pInfo->pAlbum, pInfo->albumLen);
2892                                                         pInfo->tagV2Info.bAlbumMarked = true;
2893                                                 } else if (strncmp((char *)CompTmp, "TYER", 4) == 0 && pInfo->tagV2Info.bYearMarked == false) {
2894                                                         pInfo->pYear = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->yearLen);
2895                                                         debug_msg(RELEASE, "pInfo->pYear returned = (%s), pInfo->yearLen(%d)\n", pInfo->pYear, pInfo->yearLen);
2896                                                         pInfo->tagV2Info.bYearMarked = true;
2897                                                 } else if (strncmp((char *)CompTmp, "COMM", 4) == 0 && pInfo->tagV2Info.bDescriptionMarked == false) {
2898                                                         if (realCpyFrameNum > 3) {
2899                                                                 realCpyFrameNum -= 3;
2900                                                                 tmp = 3;
2901
2902                                                                 /*pExtContent[tmp+1] value should't have encoding value */
2903                                                                 if (pExtContent[tmp] == 0x00 || pExtContent[tmp] == 0xFF || pExtContent[tmp] == 0xFE) {
2904                                                                         if ((IS_ENCODEDBY_UTF16(pExtContent + tmp) || IS_ENCODEDBY_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 2) {
2905                                                                                 while ((NEWLINE_OF_UTF16(pExtContent + tmp) || NEWLINE_OF_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 4) {
2906                                                                                         realCpyFrameNum -= 4;
2907                                                                                         tmp += 4;
2908                                                                                 }
2909
2910                                                                                 if (IS_ENCODEDBY_UTF16(pExtContent + tmp) && (realCpyFrameNum > 2)) {
2911                                                                                         realCpyFrameNum -= 2;
2912                                                                                         tmp += 2;
2913                                                                                         textEncodingType = AV_ID3V2_UTF16;
2914                                                                                 } else if (IS_ENCODEDBY_UTF16_R(pExtContent + tmp) && (realCpyFrameNum > 2)) {
2915                                                                                         realCpyFrameNum -= 2;
2916                                                                                         tmp += 2;
2917                                                                                         textEncodingType = AV_ID3V2_UTF16_BE;
2918                                                                                 } else if (IS_ENCODEDBY_UTF16(pExtContent + tmp + 1) && (realCpyFrameNum > 3)) {
2919                                                                                         realCpyFrameNum -= 3;
2920                                                                                         tmp += 3;
2921                                                                                         textEncodingType = AV_ID3V2_UTF16;
2922                                                                                 } else if (IS_ENCODEDBY_UTF16_R(pExtContent + tmp + 1)  && (realCpyFrameNum > 3)) {
2923                                                                                         realCpyFrameNum -= 3;
2924                                                                                         tmp += 3;
2925                                                                                         textEncodingType = AV_ID3V2_UTF16_BE;
2926                                                                                 } else {
2927                                                                                         debug_msg(RELEASE, "pInfo->pComment Never Get Here!!\n");
2928                                                                                 }
2929                                                                         } else {
2930                                                                                 while ((pExtContent[tmp] < 0x20) && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
2931                                                                                         realCpyFrameNum--;
2932                                                                                         tmp++;
2933                                                                                 }
2934                                                                                 textEncodingType = AV_ID3V2_ISO_8859;
2935                                                                         }
2936
2937                                                                         debug_msg(RELEASE, "tmp(%d) textEncodingType(%d), realCpyFrameNum(%d)\n", tmp, textEncodingType, realCpyFrameNum);
2938                                                                         pInfo->pComment = mmfile_string_convert((const char *)&pExtContent[tmp], realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->commentLen);
2939                                                                 } else {
2940                                                                         debug_msg(RELEASE, "failed to get Comment Info tmp(%d), purelyFramelen - encodingOffSet(%lu)\n", tmp, purelyFramelen - encodingOffSet);
2941                                                                         pInfo->commentLen = 0;
2942                                                                 }
2943                                                         } else {
2944                                                                 debug_msg(RELEASE, "Description info too small to parse realCpyFrameNum(%d)\n", realCpyFrameNum);
2945                                                                 pInfo->commentLen = 0;
2946                                                         }
2947                                                         tmp = 0;
2948
2949                                                         debug_msg(RELEASE, "pInfo->pComment returned = (%s), pInfo->commentLen(%d)\n", pInfo->pComment, pInfo->commentLen);
2950                                                         pInfo->tagV2Info.bDescriptionMarked = true;
2951                                                 } else if (strncmp((char *)CompTmp, "SYLT", 4) == 0 && pInfo->tagV2Info.bSyncLyricsMarked == false) {
2952                                                         int idx = 0;
2953                                                         int copy_len = 0;
2954                                                         int copy_start_pos = tmp;
2955                                                         AvSynclyricsInfo *synclyrics_info = NULL;
2956                                                         GList *synclyrics_info_list = NULL;
2957
2958                                                         if (realCpyFrameNum > 5) {
2959                                                                 realCpyFrameNum -= 5;
2960                                                                 tmp = 5;
2961
2962                                                                 /*pExtContent[tmp+1] value should't have encoding value */
2963                                                                 if (pExtContent[tmp] == 0x00 || pExtContent[tmp] == 0xFF || pExtContent[tmp] == 0xFE) {
2964                                                                         if ((IS_ENCODEDBY_UTF16(pExtContent + tmp) || IS_ENCODEDBY_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 2) {
2965                                                                                 while ((NEWLINE_OF_UTF16(pExtContent + tmp) || NEWLINE_OF_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 4) {
2966                                                                                         realCpyFrameNum -= 4;
2967                                                                                         tmp += 4;
2968                                                                                 }
2969
2970                                                                                 if (IS_ENCODEDBY_UTF16(pExtContent + tmp) && (realCpyFrameNum > 2)) {
2971                                                                                         realCpyFrameNum -= 2;
2972                                                                                         tmp += 2;
2973                                                                                         textEncodingType = AV_ID3V2_UTF16;
2974                                                                                 } else if (IS_ENCODEDBY_UTF16_R(pExtContent + tmp) && (realCpyFrameNum > 2)) {
2975                                                                                         realCpyFrameNum -= 2;
2976                                                                                         tmp += 2;
2977                                                                                         textEncodingType = AV_ID3V2_UTF16_BE;
2978                                                                                 } else if (IS_ENCODEDBY_UTF16(pExtContent + tmp + 1) && (realCpyFrameNum > 3)) {
2979                                                                                         realCpyFrameNum -= 3;
2980                                                                                         tmp += 3;
2981                                                                                         textEncodingType = AV_ID3V2_UTF16;
2982                                                                                 } else if (IS_ENCODEDBY_UTF16_R(pExtContent + tmp + 1)  && (realCpyFrameNum > 3)) {
2983                                                                                         realCpyFrameNum -= 3;
2984                                                                                         tmp += 3;
2985                                                                                         textEncodingType = AV_ID3V2_UTF16_BE;
2986                                                                                 } else {
2987                                                                                         debug_msg(RELEASE, "pInfo->pSyncLyrics Never Get Here!!\n");
2988                                                                                 }
2989                                                                         } else {
2990                                                                                 while ((pExtContent[tmp] < 0x20) && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
2991                                                                                         realCpyFrameNum--;
2992                                                                                         tmp++;
2993                                                                                 }
2994                                                                                 textEncodingType = AV_ID3V2_ISO_8859;
2995                                                                         }
2996
2997                                                                         debug_msg(RELEASE, "tmp(%d) textEncodingType(%d), realCpyFrameNum(%d)\n", tmp, textEncodingType, realCpyFrameNum);
2998
2999                                                                         if (realCpyFrameNum < MMFILE_SYNC_LYRIC_INFO_MIN_LEN) {
3000                                                                                 debug_msg(RELEASE, "failed to get Synchronised lyrics Info realCpyFramNum(%d)\n", realCpyFrameNum);
3001                                                                                 pInfo->syncLyricsNum = 0;
3002                                                                         } else {
3003                                                                                 if (textEncodingType == AV_ID3V2_UTF16) {
3004                                                                                         debug_warning(DEBUG, "[AV_ID3V2_UTF16] not implemented\n");
3005                                                                                 } else if (textEncodingType == AV_ID3V2_UTF16_BE) {
3006                                                                                         debug_warning(DEBUG, "[AV_ID3V2_UTF16_BE] not implemented\n");
3007                                                                                 } else {
3008                                                                                         for (idx = 0; idx < realCpyFrameNum; idx++) {
3009                                                                                                 if (pExtContent[tmp + idx] == 0x00) {
3010                                                                                                         synclyrics_info = (AvSynclyricsInfo *)malloc(sizeof(AvSynclyricsInfo));
3011
3012                                                                                                         if (synclyrics_info != NULL) {
3013                                                                                                                 if (textEncodingType == AV_ID3V2_UTF8) {
3014                                                                                                                         synclyrics_info->lyric_info = mmfile_malloc(copy_len + 1);
3015                                                                                                                         if (synclyrics_info->lyric_info != NULL) {
3016                                                                                                                                 memset(synclyrics_info->lyric_info, 0, copy_len + 1);
3017                                                                                                                                 memcpy(synclyrics_info->lyric_info, pExtContent + copy_start_pos, copy_len);
3018                                                                                                                                 synclyrics_info->lyric_info[copy_len] = '\0';
3019                                                                                                                         }
3020                                                                                                                 } else {
3021                                                                                                                         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);
3022                                                                                                                 }
3023
3024                                                                                                                 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];
3025                                                                                                                 idx += 4;
3026                                                                                                                 copy_start_pos = tmp + idx + 1;
3027                                                                                                                 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);
3028                                                                                                                 copy_len = 0;
3029                                                                                                                 synclyrics_info_list = g_list_append(synclyrics_info_list, synclyrics_info);
3030                                                                                                         }
3031                                                                                                 }
3032                                                                                                 copy_len++;
3033                                                                                         }
3034                                                                                         pInfo->pSyncLyrics = synclyrics_info_list;
3035                                                                                         pInfo->syncLyricsNum = g_list_length(pInfo->pSyncLyrics);
3036                                                                                 }
3037                                                                         }
3038                                                                 } else {
3039                                                                         debug_msg(RELEASE, "failed to get Synchronised lyrics Info tmp(%d), purelyFramelen - encodingOffSet(%lu)\n", tmp, purelyFramelen - encodingOffSet);
3040                                                                         pInfo->syncLyricsNum = 0;
3041                                                                 }
3042                                                         } else {
3043                                                                 debug_msg(RELEASE, "Synchronised lyrics too small to parse realCpyFrameNum(%d)\n", realCpyFrameNum);
3044                                                                 pInfo->syncLyricsNum = 0;
3045                                                         }
3046                                                         tmp = 0;
3047
3048                                                         //debug_msg(RELEASE, "pInfo->pSyncLyrics returned = (%s), pInfo->syncLyricsNum(%d)\n", pInfo->pSyncLyrics, pInfo->syncLyricsNum);
3049                                                         debug_msg(RELEASE, "pInfo->syncLyricsNum(%d)\n", pInfo->syncLyricsNum);
3050                                                         pInfo->tagV2Info.bSyncLyricsMarked = true;
3051                                                 } else if (strncmp((char *)CompTmp, "USLT", 4) == 0 && pInfo->tagV2Info.bUnsyncLyricsMarked == false) {
3052                                                         char *lang_info = strndup((char *)pExtContent, 3);
3053
3054                                                         if (realCpyFrameNum > 3) {
3055                                                                 realCpyFrameNum -= 3;
3056                                                                 tmp = 3;
3057
3058                                                                 /*find start of lyrics */
3059                                                                 while (1) {
3060                                                                         if (pExtContent[tmp] == 0x00) {
3061                                                                                 if (pExtContent[tmp + 1] == 0x00) {
3062                                                                                         realCpyFrameNum -= 2;
3063                                                                                         tmp += 2;
3064                                                                                 }
3065                                                                                 break;
3066                                                                         } else {
3067                                                                                 realCpyFrameNum--;
3068                                                                                 tmp++;
3069                                                                         }
3070                                                                 }
3071
3072                                                                 /*pExtContent[tmp+1] value should't have encoding value */
3073                                                                 debug_msg(RELEASE, "tpExtContent[%d] %x\n", tmp, pExtContent[tmp]);
3074
3075                                                                 if (pExtContent[tmp] == 0x00 || pExtContent[tmp] == 0xFF || pExtContent[tmp] == 0xFE) {
3076                                                                         if ((IS_ENCODEDBY_UTF16(pExtContent + tmp) || IS_ENCODEDBY_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 2) {
3077                                                                                 while ((NEWLINE_OF_UTF16(pExtContent + tmp) || NEWLINE_OF_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 4) {
3078                                                                                         realCpyFrameNum -= 4;
3079                                                                                         tmp += 4;
3080                                                                                 }
3081
3082                                                                                 if (IS_ENCODEDBY_UTF16(pExtContent + tmp) && (realCpyFrameNum > 2)) {
3083                                                                                         realCpyFrameNum -= 2;
3084                                                                                         tmp += 2;
3085                                                                                         textEncodingType = AV_ID3V2_UTF16;
3086                                                                                 } else if (IS_ENCODEDBY_UTF16_R(pExtContent + tmp) && (realCpyFrameNum > 2)) {
3087                                                                                         realCpyFrameNum -= 2;
3088                                                                                         tmp += 2;
3089                                                                                         textEncodingType = AV_ID3V2_UTF16_BE;
3090                                                                                 } else if (IS_ENCODEDBY_UTF16(pExtContent + tmp + 1) && (realCpyFrameNum > 3)) {
3091                                                                                         realCpyFrameNum -= 3;
3092                                                                                         tmp += 3;
3093                                                                                         textEncodingType = AV_ID3V2_UTF16;
3094                                                                                 } else if (IS_ENCODEDBY_UTF16_R(pExtContent + tmp + 1)  && (realCpyFrameNum > 3)) {
3095                                                                                         realCpyFrameNum -= 3;
3096                                                                                         tmp += 3;
3097                                                                                         textEncodingType = AV_ID3V2_UTF16_BE;
3098                                                                                 } else {
3099                                                                                         debug_msg(RELEASE, "pInfo->pUnsyncLyrics Never Get Here!!\n");
3100                                                                                 }
3101                                                                         } else {
3102                                                                                 while ((pExtContent[tmp] < 0x20) && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
3103                                                                                         realCpyFrameNum--;
3104                                                                                         tmp++;
3105                                                                                 }
3106                                                                                 textEncodingType = AV_ID3V2_ISO_8859;
3107                                                                         }
3108
3109                                                                         char *char_set = NULL;
3110
3111                                                                         debug_msg(RELEASE, "tmp(%d) textEncodingType(%d), realCpyFrameNum(%d)\n", tmp, textEncodingType, realCpyFrameNum);
3112
3113                                                                         if (textEncodingType == AV_ID3V2_ISO_8859) {
3114                                                                                 if (lang_info != NULL && !strcasecmp(lang_info, "KOR")) {
3115                                                                                         char_set = strdup("EUC-KR");
3116                                                                                 } else {
3117                                                                                         char_set = mmfile_get_charset((const char *)&pExtContent[tmp]);
3118                                                                                 }
3119                                                                                 _FREE_EX(lang_info);
3120                                                                         }
3121
3122                                                                         if (char_set == NULL) {
3123                                                                                 pInfo->pUnsyncLyrics = mmfile_string_convert((const char *)&pExtContent[tmp], realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->unsynclyricsLen);
3124                                                                         } else {
3125                                                                                 pInfo->pUnsyncLyrics = mmfile_string_convert((const char *)&pExtContent[tmp], realCpyFrameNum, "UTF-8", char_set, NULL, (unsigned int *)&pInfo->unsynclyricsLen);
3126                                                                                 _FREE_EX(char_set);
3127                                                                         }
3128                                                                 } else {
3129                                                                         debug_msg(RELEASE, "failed to get Unsynchronised lyrics Info tmp(%d), purelyFramelen - encodingOffSet(%lu)\n", tmp, purelyFramelen - encodingOffSet);
3130                                                                         pInfo->unsynclyricsLen = 0;
3131                                                                 }
3132                                                         } else {
3133                                                                 debug_msg(RELEASE, "Unsynchronised lyrics too small to parse realCpyFrameNum(%d)\n", realCpyFrameNum);
3134                                                                 pInfo->unsynclyricsLen = 0;
3135                                                         }
3136                                                         tmp = 0;
3137
3138                                                         debug_msg(RELEASE, "pInfo->pUnsyncLyrics returned = (%s), pInfo->unsynclyricsLen(%d)\n", pInfo->pUnsyncLyrics, pInfo->unsynclyricsLen);
3139                                                         pInfo->tagV2Info.bUnsyncLyricsMarked = true;
3140                                                         mmfile_free(lang_info);
3141                                                 } else if (strncmp((char *)CompTmp, "TCON", 4) == 0 && pInfo->tagV2Info.bGenreMarked == false) {
3142                                                         pInfo->pGenre = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->genreLen);
3143                                                         debug_msg(RELEASE, "pInfo->pGenre returned = (%s), pInfo->genreLen(%d)\n", pInfo->pGenre, pInfo->genreLen);
3144
3145                                                         if ((pInfo->pGenre != NULL) && (pInfo->genreLen > 0)) {
3146                                                                 bool ret = FALSE;
3147                                                                 int int_genre = -1;
3148
3149                                                                 ret = is_numeric(pInfo->pGenre, pInfo->genreLen);
3150
3151                                                                 if (ret == TRUE) {
3152                                                                         ret = safe_atoi(pInfo->pGenre, &int_genre);
3153                                                                         if (ret == TRUE) {
3154                                                                                 debug_msg(RELEASE, "genre information is inteager [%d]\n", int_genre);
3155
3156                                                                                 /*Change int to string */
3157                                                                                 if ((0 <= int_genre) && (int_genre < GENRE_COUNT - 1)) {
3158                                                                                         /*save genreinfo like "(123)". mm_file_id3tag_restore_content_info convert it to string*/
3159                                                                                         char tmp_genre[6] = {0, };      /*ex. "(123)+NULL"*/
3160                                                                                         int tmp_genre_len = 0;
3161
3162                                                                                         memset(tmp_genre, 0, 6);
3163                                                                                         snprintf(tmp_genre, sizeof(tmp_genre), "(%d)", int_genre);
3164
3165                                                                                         tmp_genre_len = strlen(tmp_genre);
3166                                                                                         if (tmp_genre_len > 0) {
3167                                                                                                 if (pInfo->pGenre) _FREE_EX(pInfo->pGenre);
3168                                                                                                 pInfo->pGenre = mmfile_malloc(sizeof(char) * (tmp_genre_len + 1));
3169                                                                                                 if (pInfo->pGenre) {
3170                                                                                                         SAFE_STRLCPY(pInfo->pGenre, tmp_genre, tmp_genre_len + 1);
3171                                                                                                 }
3172                                                                                         }
3173                                                                                 }
3174                                                                         } else {
3175                                                                                 debug_msg(RELEASE, "genre information is wrong inteager [%s]\n", pInfo->pGenre);
3176                                                                         }
3177                                                                 }
3178                                                         }
3179
3180                                                         pInfo->tagV2Info.bGenreMarked = true;
3181                                                 } else if (strncmp((char *)CompTmp, "TRCK", 4) == 0 && pInfo->tagV2Info.bTrackNumMarked == false) {
3182                                                         pInfo->pTrackNum = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->tracknumLen);
3183                                                         debug_msg(RELEASE, "pInfo->pTrackNum returned = (%s), pInfo->tracknumLen(%d)\n", pInfo->pTrackNum, pInfo->tracknumLen);
3184                                                         pInfo->tagV2Info.bTrackNumMarked = true;
3185                                                 } else if (strncmp((char *)CompTmp, "TENC", 4) == 0 && pInfo->tagV2Info.bEncByMarked == false) {
3186                                                         pInfo->pEncBy = mmfile_string_convert((char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->encbyLen);
3187                                                         debug_msg(RELEASE, "pInfo->pEncBy returned = (%s), pInfo->encbyLen(%d)\n", pInfo->pEncBy, pInfo->encbyLen);
3188                                                         pInfo->tagV2Info.bEncByMarked = true;
3189                                                 } else if (strncmp((char *)CompTmp, "WXXX", 4) == 0 && pInfo->tagV2Info.bURLMarked == false) {
3190                                                         pInfo->pURL = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->urlLen);
3191                                                         debug_msg(RELEASE, "pInfo->pURL returned = (%s), pInfo->urlLen(%d)\n", pInfo->pURL, pInfo->urlLen);
3192                                                         pInfo->tagV2Info.bURLMarked = true;
3193                                                 } else if (strncmp((char *)CompTmp, "TCOP", 4) == 0 && pInfo->tagV2Info.bCopyRightMarked == false) {
3194                                                         pInfo->pCopyright = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->copyrightLen);
3195                                                         debug_msg(RELEASE, "pInfo->pCopyright returned = (%s), pInfo->copyrightLen(%d)\n", pInfo->pCopyright, pInfo->copyrightLen);
3196                                                         pInfo->tagV2Info.bCopyRightMarked = true;
3197                                                 } else if (strncmp((char *)CompTmp, "TOPE", 4) == 0 && pInfo->tagV2Info.bOriginArtistMarked == false) {
3198                                                         pInfo->pOriginArtist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->originartistLen);
3199                                                         debug_msg(RELEASE, "pInfo->pOriginArtist returned = (%s), pInfo->originartistLen(%d)\n", pInfo->pOriginArtist, pInfo->originartistLen);
3200                                                         pInfo->tagV2Info.bOriginArtistMarked = true;
3201                                                 } else if (strncmp((char *)CompTmp, "TCOM", 4) == 0 && pInfo->tagV2Info.bComposerMarked == false) {
3202                                                         pInfo->pComposer = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->composerLen);
3203                                                         debug_msg(RELEASE, "pInfo->pComposer returned = (%s), pInfo->composerLen(%d)\n", pInfo->pComposer, pInfo->composerLen);
3204                                                         pInfo->tagV2Info.bComposerMarked = true;
3205                                                 } else if (strncmp((char *)CompTmp, "TRDA", 4) == 0 && pInfo->tagV2Info.bRecDateMarked == false) {
3206                                                         pInfo->pRecDate = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->recdateLen);
3207                                                         debug_msg(RELEASE, "pInfo->pRecDate returned = (%s), pInfo->recdateLen(%d)\n", pInfo->pRecDate, pInfo->recdateLen);
3208                                                         pInfo->tagV2Info.bRecDateMarked = true;
3209                                                 } else if (strncmp((char *)CompTmp, "APIC", 4) == 0 && pInfo->tagV2Info.bImageMarked == false && realCpyFrameNum <= 2000000) {
3210                                                         debug_msg(DEBUG, "text encoding %d \n", textEncodingType);
3211
3212                                                         if (pExtContent[0] != '\0') {
3213                                                                 for (inx = 0; inx < MP3_ID3_IMAGE_MIME_TYPE_MAX_LENGTH - 1; inx++)
3214                                                                         pInfo->imageInfo.imageMIMEType[inx] = '\0';/*ini mimetype variable */
3215
3216                                                                 while ((checkImgMimeTypeMax < MP3_ID3_IMAGE_MIME_TYPE_MAX_LENGTH - 1) && pExtContent[checkImgMimeTypeMax] != '\0') {
3217                                                                         pInfo->imageInfo.imageMIMEType[checkImgMimeTypeMax] = pExtContent[checkImgMimeTypeMax];
3218                                                                         checkImgMimeTypeMax++;
3219                                                                 }
3220                                                                 pInfo->imageInfo.imgMimetypeLen = checkImgMimeTypeMax;
3221                                                         } else {
3222                                                                 pInfo->imageInfo.imgMimetypeLen = 0;
3223                                                                 debug_msg(RELEASE, "APIC image's not included to MIME type\n");
3224                                                         }
3225
3226                                                         imgstartOffset += checkImgMimeTypeMax;
3227
3228                                                         if (strncmp(pInfo->imageInfo.imageMIMEType, MIME_PRFIX, strlen(MIME_PRFIX)) != 0) {
3229                                                                 pInfo->imageInfo.imgMimetypeLen = 0;
3230                                                                 debug_error(DEBUG, "APIC NOT VALID");
3231                                                                 continue;
3232                                                         }
3233
3234                                                         if ((pExtContent[imgstartOffset] == '\0') && (realCpyFrameNum - imgstartOffset > 0)) {
3235                                                                 imgstartOffset++;/*endofMIME(1byte) */
3236                                                                 debug_msg(RELEASE, "after scaning Mime type imgstartOffset(%d) value!\n", imgstartOffset);
3237
3238                                                                 if (pExtContent[imgstartOffset] < AV_ID3V2_PICTURE_TYPE_MAX) {
3239                                                                         pInfo->imageInfo.pictureType = pExtContent[imgstartOffset];
3240                                                                 } else {
3241                                                                         debug_msg(RELEASE, "APIC image has invalid picture type(0x%x)\n", pExtContent[imgstartOffset]);
3242                                                                 }
3243                                                                 imgstartOffset++;/*PictureType(1byte) */
3244                                                                 debug_msg(RELEASE, "after scaning PictureType imgstartOffset(%d) value!\n", imgstartOffset);
3245
3246                                                                 if (pExtContent[imgstartOffset] != 0x0) {
3247                                                                         int cur_pos = 0;
3248                                                                         int dis_len = 0;
3249                                                                         int new_dis_len = 0;
3250                                                                         char *tmp_desc = NULL;
3251
3252                                                                         while (1) {
3253                                                                                 if (pExtContent[imgstartOffset + cur_pos] == '\0') {
3254                                                                                         if (realCpyFrameNum < imgstartOffset + cur_pos) {
3255                                                                                                 debug_error(DEBUG, "End of APIC Tag %d %d %d\n", realCpyFrameNum, imgstartOffset, cur_pos);
3256                                                                                                 break;
3257                                                                                         }
3258                                                                                         /*check end of image description*/
3259                                                                                         if ((pExtContent[imgstartOffset + cur_pos + 1] == gTagJPEGHeader[0]) ||
3260                                                                                             (pExtContent[imgstartOffset + cur_pos + 1] == gTagPNGHeader[0])) {
3261                                                                                                 debug_msg(RELEASE, "length of description (%d)", cur_pos);
3262                                                                                                 break;
3263                                                                                         }
3264                                                                                 }
3265                                                                                 cur_pos++;
3266                                                                         }
3267
3268                                                                         dis_len = cur_pos + 1;
3269
3270                                                                         tmp_desc = mmfile_malloc(sizeof(char) * dis_len);
3271                                                                         if (tmp_desc != NULL) {
3272                                                                                 memcpy(tmp_desc, pExtContent + imgstartOffset, dis_len);
3273
3274                                                                                 /*convert description*/
3275                                                                                 pInfo->imageInfo.imageDescription = mmfile_string_convert(tmp_desc, dis_len, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&new_dis_len);
3276                                                                                 debug_msg(RELEASE, "new_desc %s(%d)\n", pInfo->imageInfo.imageDescription, new_dis_len);
3277                                                                                 mmfile_free(tmp_desc);
3278
3279                                                                                 pInfo->imageInfo.imgDesLen = new_dis_len; /**/
3280                                                                         }
3281
3282                                                                         imgstartOffset += cur_pos;
3283                                                                 } else {
3284                                                                         pInfo->imageInfo.imgDesLen = 0;
3285                                                                         debug_msg(RELEASE, "APIC image's not included to Description!!!\n");
3286                                                                 }
3287
3288                                                                 if ((pExtContent[imgstartOffset] == '\0') && (realCpyFrameNum - imgstartOffset > 0)) {
3289                                                                         imgstartOffset++; /* endofDesceriptionType(1byte) */
3290
3291                                                                         while (pExtContent[imgstartOffset] == '\0') {   /*some content has useless '\0' in front of picture data */
3292                                                                                 imgstartOffset++;
3293                                                                         }
3294
3295                                                                         debug_msg(RELEASE, "after scaning imgDescription imgstartOffset(%d) value!\n", imgstartOffset);
3296
3297                                                                         if (realCpyFrameNum - imgstartOffset > 0) {
3298                                                                                 pInfo->imageInfo.imageLen = realCpyFrameNum - imgstartOffset;
3299                                                                                 pInfo->imageInfo.pImageBuf = mmfile_malloc(pInfo->imageInfo.imageLen + 1);
3300
3301                                                                                 if (pInfo->imageInfo.pImageBuf != NULL) {
3302                                                                                         memcpy(pInfo->imageInfo.pImageBuf, pExtContent + imgstartOffset, pInfo->imageInfo.imageLen);
3303                                                                                         pInfo->imageInfo.pImageBuf[pInfo->imageInfo.imageLen] = 0;
3304                                                                                 }
3305
3306                                                                                 if (IS_INCLUDE_URL(pInfo->imageInfo.imageMIMEType))
3307                                                                                         pInfo->imageInfo.bURLInfo = true; /*if mimetype is "-->", image date has an URL */
3308                                                                         } else {
3309                                                                                 debug_msg(RELEASE, "No APIC image!! realCpyFrameNum(%d) - imgstartOffset(%d)\n", realCpyFrameNum, imgstartOffset);
3310                                                                         }
3311                                                                         debug_msg(RELEASE, "pInfo->imageInfo.imageLen(%d), imgstartOffset(%d)!\n", pInfo->imageInfo.imageLen, imgstartOffset);
3312                                                                 } else {
3313                                                                         debug_msg(RELEASE, "pExtContent[imgstartOffset](%d) value should setted NULL value for end of description! realCpyFrameNum - imgstartOffset(%d)\n",
3314                                                                                         pExtContent[imgstartOffset], realCpyFrameNum - imgstartOffset);
3315                                                                 }
3316                                                         } else {
3317                                                                 debug_msg(RELEASE, "pExtContent[imgstartOffset](%d) value should setted NULL value for end of mimetype! realCpyFrameNum - imgstartOffset(%d)\n",
3318                                                                                         pExtContent[imgstartOffset], realCpyFrameNum - imgstartOffset);
3319                                                         }
3320
3321                                                         checkImgMimeTypeMax = 0;
3322                                                         inx = 0;
3323                                                         imgstartOffset = 0;
3324                                                         pInfo->tagV2Info.bImageMarked = true;
3325
3326                                                 } else {
3327                                                         debug_msg(RELEASE, "CompTmp(%s) This Frame ID currently not Supports!!\n", CompTmp);
3328                                                 }
3329                                         }
3330
3331                                 } else {
3332                                         debug_msg(RELEASE, "All of the pExtContent Values are NULL\n");
3333                                 }
3334                         } else {
3335                                 curPos += purelyFramelen;
3336                                 if (purelyFramelen != 0)
3337                                         needToloopv2taglen = MP3_TAGv2_23_TXT_HEADER_LEN;
3338
3339                                 debug_msg(RELEASE, "This Frame's size is Zero! purelyFramelen(%lu)\n", purelyFramelen);
3340                         }
3341
3342                         if (pExtContent)        _FREE_EX(pExtContent);
3343                         memset(CompTmp, 0, 4);
3344
3345                         if (curPos < taglen) {
3346                                 needToloopv2taglen -= oneFrameLen;
3347                                 v2numOfFrames++;
3348                         } else
3349                                 needToloopv2taglen = MP3_TAGv2_23_TXT_HEADER_LEN;
3350                         oneFrameLen = 0;
3351                         encodingOffSet = 0;
3352                         realCpyFrameNum = 0;
3353                         textEncodingType = 0;
3354                         purelyFramelen = 0;
3355
3356                 }
3357         }
3358
3359         release_characterset_array(charset_array);
3360
3361         if (taglen)
3362                 return true;
3363         else
3364                 return false;
3365
3366 }
3367
3368 EXPORT_API
3369 bool mm_file_id3tag_parse_v224(AvFileContentInfo *pInfo, unsigned char *buffer)
3370 {
3371         unsigned long taglen = 0;
3372         unsigned long needToloopv2taglen;
3373         unsigned long oneFrameLen = 0;
3374         unsigned long v2numOfFrames = 0;
3375         unsigned long curPos = 0;
3376         char CompTmp[5];
3377         unsigned char *pExtContent = NULL;
3378         unsigned long purelyFramelen = 0;
3379         unsigned int encodingOffSet = 0;
3380         int inx = 0, realCpyFrameNum = 0, checkImgMimeTypeMax = 0, imgstartOffset = 0,  tmp = 0;
3381         unsigned int textEncodingType = 0;
3382         char **charset_array = NULL;
3383         const char *MIME_PRFIX = "image/";
3384
3385         make_characterset_array(&charset_array);
3386
3387         init_content_info(pInfo);
3388
3389         taglen = pInfo->tagV2Info.tagLen;
3390         needToloopv2taglen = taglen - MP3_TAGv2_HEADER_LEN;
3391         curPos = MP3_TAGv2_HEADER_LEN;
3392
3393         debug_msg(RELEASE, "ID3tag v224--------------------------------------------------------------\n");
3394
3395         /* check Extended Header */
3396         if (buffer[5] & 0x40) {
3397                 /* if extended header exists, skip it*/
3398                 int extendedHeaderLen = (unsigned long)buffer[10] << 21 | (unsigned long)buffer[11] << 14 | (unsigned long)buffer[12] << 7  | (unsigned long)buffer[13];
3399
3400                 debug_msg(RELEASE, "--------------- extendedHeaderLen = %d\n", extendedHeaderLen);
3401
3402                 if (extendedHeaderLen > (int)(taglen - curPos)) {
3403                         debug_error(DEBUG, "extended header too long.\n");
3404                 } else {
3405                         curPos += extendedHeaderLen;
3406                 }
3407         }
3408
3409         if (needToloopv2taglen - MP3_TAGv2_23_TXT_HEADER_LEN > MP3_TAGv2_23_TXT_HEADER_LEN) {
3410                 v2numOfFrames = 1;
3411                 while (needToloopv2taglen > MP3_TAGv2_23_TXT_HEADER_LEN) {
3412                         if ((buffer[curPos] < '0' || buffer[curPos] > 'Z') || (buffer[curPos + 1] < '0' || buffer[curPos + 1] > 'Z')
3413                             || (buffer[curPos + 2] < '0' || buffer[curPos + 2] > 'Z') || (buffer[curPos + 3] < '0' || buffer[curPos + 3] > 'Z'))
3414                                 break;
3415
3416                         memcpy(CompTmp, &buffer[curPos], 4);
3417
3418                         CompTmp[4] = 0;
3419                         oneFrameLen = MP3_TAGv2_23_TXT_HEADER_LEN;
3420                         oneFrameLen += (unsigned long)buffer[4 + curPos] << 21 | (unsigned long)buffer[5 + curPos] << 14
3421                                                 | (unsigned long)buffer[6 + curPos] << 7 | (unsigned long)buffer[7 + curPos];
3422                         if (oneFrameLen > taglen - curPos)
3423                                 break;
3424
3425                         purelyFramelen = oneFrameLen - MP3_TAGv2_23_TXT_HEADER_LEN;
3426                         curPos += MP3_TAGv2_23_TXT_HEADER_LEN;
3427
3428                         debug_msg(RELEASE, "-----------------------------------------------------------------------------------\n");
3429
3430                         if (oneFrameLen > MP3_TAGv2_23_TXT_HEADER_LEN && purelyFramelen <= taglen - curPos) {
3431                                 curPos += purelyFramelen;
3432
3433                                 /*in case of UTF 16 encoding */
3434                                 /*buffer+(curPos-purelyFramelen) data should '0x01' but in order to expansion, we don't accurately check the value. */
3435                                 if (IS_ENCODEDBY_UTF16(buffer + (curPos - purelyFramelen))) {
3436                                         encodingOffSet = 2;
3437                                         textEncodingType = AV_ID3V2_UTF16;
3438                                 } else if (IS_ENCODEDBY_UTF16_R(buffer + (curPos - purelyFramelen))) {
3439                                         encodingOffSet = 2;
3440                                         textEncodingType = AV_ID3V2_UTF16_BE;
3441                                 } else if (IS_ENCODEDBY_UTF16(buffer + (curPos - purelyFramelen + 1))) {
3442                                         encodingOffSet = 3;
3443                                         textEncodingType = AV_ID3V2_UTF16;
3444                                 } else if (IS_ENCODEDBY_UTF16_R(buffer + (curPos - purelyFramelen + 1))) {
3445                                         encodingOffSet = 3;
3446                                         textEncodingType = AV_ID3V2_UTF16_BE;
3447                                 } else {
3448                                         /*in case of UTF-16 BE encoding */
3449                                         if (buffer[curPos - purelyFramelen] == 0x02) {
3450                                                 encodingOffSet = 1;
3451                                                 while ((buffer[curPos - purelyFramelen + encodingOffSet] == '\0') && (encodingOffSet < purelyFramelen))
3452                                                         encodingOffSet++;/*null skip! */
3453                                                 textEncodingType = AV_ID3V2_UTF16_BE;
3454                                         }
3455                                         /*in case of UTF8 encoding */
3456                                         else if (buffer[curPos - purelyFramelen] == 0x03) {
3457                                                 encodingOffSet = 1;
3458                                                 while ((buffer[curPos - purelyFramelen + encodingOffSet] == '\0') && (encodingOffSet < purelyFramelen))
3459                                                         encodingOffSet++;/*null skip! */
3460                                                 textEncodingType = AV_ID3V2_UTF8;
3461                                         }
3462                                         /*in case of ISO-8859-1 encoding */
3463                                         else {
3464                                                 /*buffer+(curPos-purelyFramelen) data should 0x00 but in order to expansion, we don't accurately check the value. */
3465                                                 encodingOffSet = 1;
3466                                                 while ((buffer[curPos - purelyFramelen + encodingOffSet] < 0x20) && (encodingOffSet < purelyFramelen))
3467                                                         encodingOffSet++;/*less than 0x20 value skip! */
3468                                                 textEncodingType = AV_ID3V2_ISO_8859;
3469                                         }
3470                                 }
3471
3472                                 if (pExtContent)        _FREE_EX(pExtContent);
3473
3474                                 if (encodingOffSet < purelyFramelen) {
3475                                         realCpyFrameNum = purelyFramelen - encodingOffSet;
3476                                         pExtContent = mmfile_malloc(realCpyFrameNum + 3);
3477
3478                                         if (pExtContent == NULL) {
3479                                                 debug_error(DEBUG, "out of memoryu for id3tag parse\n");
3480                                                 continue;
3481                                         }
3482
3483                                         memset(pExtContent, '\0', realCpyFrameNum + 3);
3484
3485                                         if (textEncodingType != AV_ID3V2_UTF16 && textEncodingType != AV_ID3V2_UTF16_BE) {
3486                                                 if (CompTmp[0] == 'T' || (strcmp(CompTmp, "APIC") == 0)) {
3487                                                         debug_msg(RELEASE, "get the new text ecoding type\n");
3488                                                         textEncodingType = buffer[curPos - purelyFramelen + encodingOffSet - 1];
3489                                                 }
3490                                         }
3491
3492                                         if (textEncodingType > AV_ID3V2_MAX) {
3493                                                 debug_msg(DEBUG, "WRONG ENCOIDNG TYPE [%d], FRAME[%s]\n", textEncodingType, (char *)CompTmp);
3494                                                 continue;
3495                                         }
3496
3497                                         memcpy(pExtContent, &buffer[curPos - purelyFramelen + encodingOffSet], purelyFramelen - encodingOffSet);
3498
3499                                         if (realCpyFrameNum > 0) {
3500                                                 if (strncmp((char *)CompTmp, "TIT2", 4) == 0 && pInfo->tagV2Info.bTitleMarked == false) {
3501                                                         if (textEncodingType == AV_ID3V2_UTF8) {
3502                                                                 pInfo->pTitle = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3503                                                                 if (pInfo->pTitle) {
3504                                                                         memcpy(pInfo->pTitle, pExtContent, realCpyFrameNum);
3505                                                                         pInfo->pTitle[realCpyFrameNum] = '\0';
3506                                                                         /*string copy with '\0'*/
3507                                                                         pInfo->titleLen = realCpyFrameNum;
3508                                                                         _STRNCPY_EX(pInfo->pTitle, pExtContent, pInfo->titleLen);
3509                                                                 }
3510                                                         } else {
3511                                                                 pInfo->pTitle = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->titleLen);
3512                                                         }
3513
3514                                                         debug_msg(RELEASE, "pInfo->pTitle returned = (%s), pInfo->titleLen(%d)\n", pInfo->pTitle, pInfo->titleLen);
3515                                                         pInfo->tagV2Info.bTitleMarked = true;
3516
3517                                                 } else if (strncmp((char *)CompTmp, "TPE1", 4) == 0 && pInfo->tagV2Info.bArtistMarked == false) {
3518                                                         if (textEncodingType == AV_ID3V2_UTF8) {
3519                                                                 pInfo->pArtist = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3520                                                                 if (pInfo->pArtist) {
3521                                                                         memcpy(pInfo->pArtist, pExtContent, realCpyFrameNum);
3522                                                                         pInfo->pArtist[realCpyFrameNum] = '\0';
3523                                                                         /*string copy with '\0'*/
3524                                                                         pInfo->artistLen = realCpyFrameNum;
3525                                                                         _STRNCPY_EX(pInfo->pArtist, pExtContent, pInfo->artistLen);
3526                                                                 }
3527                                                         } else {
3528                                                                 pInfo->pArtist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->artistLen);
3529                                                         }
3530
3531
3532                                                         debug_msg(RELEASE, "pInfo->pArtist returned = (%s), pInfo->artistLen(%d)\n", pInfo->pArtist, pInfo->artistLen);
3533                                                         pInfo->tagV2Info.bArtistMarked = true;
3534                                                 } else if (strncmp((char *)CompTmp, "TPE2", 4) == 0 && pInfo->tagV2Info.bAlbum_ArtistMarked == false) {
3535                                                         if (textEncodingType == AV_ID3V2_UTF8) {
3536                                                                 pInfo->pAlbum_Artist = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3537                                                                 if (pInfo->pAlbum_Artist) {
3538                                                                         memcpy(pInfo->pAlbum_Artist, pExtContent, realCpyFrameNum);
3539                                                                         pInfo->pAlbum_Artist[realCpyFrameNum] = '\0';
3540                                                                         /*string copy with '\0'*/
3541                                                                         pInfo->album_artistLen = realCpyFrameNum;
3542                                                                         _STRNCPY_EX(pInfo->pAlbum_Artist, pExtContent, pInfo->album_artistLen);
3543                                                                 }
3544                                                         } else {
3545                                                                 pInfo->pAlbum_Artist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->album_artistLen);
3546                                                         }
3547
3548                                                         debug_msg(RELEASE, "pInfo->pAlbum_Artist returned = (%s), pInfo->album_artistLen(%d)\n", pInfo->pAlbum_Artist, pInfo->album_artistLen);
3549                                                         pInfo->tagV2Info.bAlbum_ArtistMarked = true;
3550                                                 } else if (strncmp((char *)CompTmp, "TPE3", 4) == 0 && pInfo->tagV2Info.bConductorMarked == false) {
3551                                                         if (textEncodingType == AV_ID3V2_UTF8) {
3552                                                                 pInfo->pConductor = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3553                                                                 if (pInfo->pConductor) {
3554                                                                         memcpy(pInfo->pConductor, pExtContent, realCpyFrameNum);
3555                                                                         pInfo->pConductor[realCpyFrameNum] = '\0';
3556                                                                         /*string copy with '\0'*/
3557                                                                         pInfo->conductorLen = realCpyFrameNum;
3558                                                                         _STRNCPY_EX(pInfo->pConductor, pExtContent, pInfo->conductorLen);
3559                                                                 }
3560                                                         } else {
3561                                                                 pInfo->pConductor = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->conductorLen);
3562                                                         }
3563
3564                                                         debug_msg(RELEASE, "pInfo->pConductor returned = (%s), pInfo->conductorLen(%d)\n", pInfo->pConductor, pInfo->conductorLen);
3565                                                         pInfo->tagV2Info.bConductorMarked = true;
3566                                                 } else if (strncmp((char *)CompTmp, "TALB", 4) == 0 && pInfo->tagV2Info.bAlbumMarked == false) {
3567                                                         if (textEncodingType == AV_ID3V2_UTF8) {
3568                                                                 pInfo->pAlbum = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3569                                                                 if (pInfo->pAlbum) {
3570                                                                         memcpy(pInfo->pAlbum, pExtContent, realCpyFrameNum);
3571                                                                         pInfo->pAlbum[realCpyFrameNum] = '\0';
3572                                                                         /*string copy with '\0'*/
3573                                                                         pInfo->albumLen = realCpyFrameNum;
3574                                                                         _STRNCPY_EX(pInfo->pAlbum, pExtContent, pInfo->albumLen);
3575                                                                 }
3576                                                         } else {
3577                                                                 pInfo->pAlbum = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->albumLen);
3578                                                         }
3579
3580                                                         debug_msg(RELEASE, "pInfo->pAlbum returned = (%s), pInfo->albumLen(%d)\n", pInfo->pAlbum, pInfo->albumLen);
3581                                                         pInfo->tagV2Info.bAlbumMarked = true;
3582                                                 } 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 */
3583                                                         if (textEncodingType == AV_ID3V2_UTF8) {
3584                                                                 pInfo->pYear = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3585                                                                 if (pInfo->pYear) {
3586                                                                         memcpy(pInfo->pYear, pExtContent, realCpyFrameNum);
3587                                                                         pInfo->pYear[realCpyFrameNum] = '\0';
3588                                                                         /*string copy with '\0'*/
3589                                                                         pInfo->yearLen = realCpyFrameNum;
3590                                                                         _STRNCPY_EX(pInfo->pYear, pExtContent, pInfo->yearLen);
3591                                                                 }
3592                                                         } else {
3593                                                                 pInfo->pYear = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->yearLen);
3594                                                         }
3595
3596                                                         debug_msg(RELEASE, "pInfo->pYear returned = (%s), pInfo->yearLen(%d)\n", pInfo->pYear, pInfo->yearLen);
3597                                                         pInfo->tagV2Info.bYearMarked = true;
3598                                                 } else if (strncmp((char *)CompTmp, "COMM", 4) == 0 && pInfo->tagV2Info.bDescriptionMarked == false) {
3599                                                         if (realCpyFrameNum > 3) {
3600                                                                 realCpyFrameNum -= 3;
3601                                                                 tmp = 3;
3602
3603                                                                 if (textEncodingType == AV_ID3V2_UTF16 || textEncodingType == AV_ID3V2_UTF16_BE) {
3604                                                                         while ((NEWLINE_OF_UTF16(pExtContent + tmp) || NEWLINE_OF_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 4) {
3605                                                                                 realCpyFrameNum -= 4;
3606                                                                                 tmp += 4;
3607                                                                         }
3608
3609                                                                         if ((IS_ENCODEDBY_UTF16(pExtContent + tmp) || IS_ENCODEDBY_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 2) {
3610                                                                                 realCpyFrameNum -= 2;
3611                                                                                 tmp += 2;
3612                                                                                 textEncodingType = AV_ID3V2_UTF16;
3613                                                                         } else {
3614                                                                                 debug_msg(RELEASE, "pInfo->pComment Never Get Here!!\n");
3615                                                                         }
3616                                                                 } else if (textEncodingType == AV_ID3V2_UTF8) {
3617                                                                         while (pExtContent[tmp] < 0x20 && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
3618                                                                                 realCpyFrameNum--;
3619                                                                                 tmp++;
3620                                                                         }
3621                                                                         textEncodingType = AV_ID3V2_UTF8;
3622                                                                 } else {
3623                                                                         while (pExtContent[tmp] < 0x20 && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
3624                                                                                 realCpyFrameNum--;
3625                                                                                 tmp++;
3626                                                                         }
3627                                                                         textEncodingType = AV_ID3V2_ISO_8859;
3628                                                                 }
3629
3630                                                                 debug_msg(RELEASE, "tmp(%d) textEncodingType(%d), realCpyFrameNum(%d)\n", tmp, textEncodingType, realCpyFrameNum);
3631
3632                                                                 if (textEncodingType == AV_ID3V2_UTF8) {
3633                                                                         pInfo->pComment = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3634                                                                         if (pInfo->pComment) {
3635                                                                                 memset(pInfo->pComment, 0, (realCpyFrameNum + 2));
3636                                                                                 memcpy(pInfo->pComment, pExtContent + tmp, realCpyFrameNum);
3637                                                                                 pInfo->pComment[realCpyFrameNum] = '\0';
3638                                                                                 /*string copy with '\0'*/
3639                                                                                 pInfo->commentLen = realCpyFrameNum;
3640                                                                                 _STRNCPY_EX(pInfo->pComment, pExtContent, pInfo->commentLen);
3641                                                                         }
3642                                                                 } else {
3643                                                                         pInfo->pComment = mmfile_string_convert((const char *)&pExtContent[tmp], realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->commentLen);
3644                                                                 }
3645                                                         } else {
3646                                                                 debug_msg(RELEASE, "Description info too small to parse realCpyFrameNum(%d)\n", realCpyFrameNum);
3647                                                         }
3648
3649                                                         tmp = 0;
3650
3651                                                         debug_msg(RELEASE, "pInfo->pComment returned = (%s), pInfo->commentLen(%d)\n", pInfo->pComment, pInfo->commentLen);
3652                                                         pInfo->tagV2Info.bDescriptionMarked = true;
3653                                                 } else if (strncmp((char *)CompTmp, "SYLT", 4) == 0 && pInfo->tagV2Info.bSyncLyricsMarked == false) {
3654                                                         int idx = 0;
3655                                                         int copy_len = 0;
3656                                                         int copy_start_pos = tmp;
3657                                                         AvSynclyricsInfo *synclyrics_info = NULL;
3658                                                         GList *synclyrics_info_list = NULL;
3659
3660                                                         if (realCpyFrameNum > 5) {
3661                                                                 realCpyFrameNum -= 5;
3662                                                                 tmp = 5;
3663
3664                                                                 if (textEncodingType == AV_ID3V2_UTF16 || textEncodingType == AV_ID3V2_UTF16_BE) {
3665                                                                         while ((NEWLINE_OF_UTF16(pExtContent + tmp) || NEWLINE_OF_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 4) {
3666                                                                                 realCpyFrameNum -= 4;
3667                                                                                 tmp += 4;
3668                                                                         }
3669
3670                                                                         if ((IS_ENCODEDBY_UTF16(pExtContent + tmp) || IS_ENCODEDBY_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 2) {
3671                                                                                 realCpyFrameNum -= 2;
3672                                                                                 tmp += 2;
3673                                                                                 textEncodingType = AV_ID3V2_UTF16;
3674                                                                         } else {
3675                                                                                 debug_msg(RELEASE, "pInfo->pSyncLyrics Never Get Here!!\n");
3676                                                                         }
3677                                                                 } else if (textEncodingType == AV_ID3V2_UTF8) {
3678                                                                         while (pExtContent[tmp] < 0x20 && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
3679                                                                                 realCpyFrameNum--;
3680                                                                                 tmp++;
3681                                                                         }
3682                                                                         textEncodingType = AV_ID3V2_UTF8;
3683                                                                 } else {
3684                                                                         while (pExtContent[tmp] < 0x20 && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
3685                                                                                 realCpyFrameNum--;
3686                                                                                 tmp++;
3687                                                                         }
3688                                                                         textEncodingType = AV_ID3V2_ISO_8859;
3689                                                                 }
3690
3691                                                                 debug_msg(RELEASE, "tmp(%d) textEncodingType(%d), realCpyFrameNum(%d)\n", tmp, textEncodingType, realCpyFrameNum);
3692
3693                                                                 if (realCpyFrameNum < MMFILE_SYNC_LYRIC_INFO_MIN_LEN) {
3694                                                                         debug_msg(RELEASE, "failed to get Synchronised lyrics Info realCpyFramNum(%d)\n", realCpyFrameNum);
3695                                                                         pInfo->syncLyricsNum = 0;
3696                                                                 } else {
3697                                                                         if (textEncodingType == AV_ID3V2_UTF16) {
3698                                                                                 debug_warning(DEBUG, "[AV_ID3V2_UTF16] not implemented\n");
3699                                                                         } else if (textEncodingType == AV_ID3V2_UTF16_BE) {
3700                                                                                 debug_warning(DEBUG, "[AV_ID3V2_UTF16_BE] not implemented\n");
3701                                                                         } else {
3702                                                                                 for (idx = 0; idx < realCpyFrameNum; idx++) {
3703                                                                                         if (pExtContent[tmp + idx] == 0x00) {
3704                                                                                                 synclyrics_info = (AvSynclyricsInfo *)mmfile_malloc(sizeof(AvSynclyricsInfo));
3705                                                                                                 if (synclyrics_info) {
3706                                                                                                         if (textEncodingType == AV_ID3V2_UTF8) {
3707                                                                                                                 synclyrics_info->lyric_info = mmfile_malloc(copy_len + 1);
3708                                                                                                                 if (synclyrics_info->lyric_info) {
3709                                                                                                                         memset(synclyrics_info->lyric_info, 0, copy_len + 1);
3710                                                                                                                         memcpy(synclyrics_info->lyric_info, pExtContent + copy_start_pos, copy_len);
3711                                                                                                                         synclyrics_info->lyric_info[copy_len] = '\0';
3712                                                                                                                 }
3713                                                                                                         } else {
3714                                                                                                                 synclyrics_info->lyric_info = mmfile_string_convert((const char *)&pExtContent[copy_start_pos], copy_len, "UTF-8", charset_array[textEncodingType], NULL, NULL);
3715                                                                                                         }
3716
3717                                                                                                         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];
3718                                                                                                         idx += 4;
3719                                                                                                         copy_start_pos = tmp + idx + 1;
3720                                                                                                         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);
3721                                                                                                         copy_len = 0;
3722                                                                                                         synclyrics_info_list = g_list_append(synclyrics_info_list, synclyrics_info);
3723                                                                                                 }
3724                                                                                         }
3725                                                                                         copy_len++;
3726                                                                                 }
3727                                                                                 pInfo->pSyncLyrics = synclyrics_info_list;
3728                                                                                 pInfo->syncLyricsNum = g_list_length(pInfo->pSyncLyrics);
3729                                                                         }
3730                                                                 }
3731                                                         } else {
3732                                                                 debug_msg(RELEASE, "SyncLyrics info too small to parse realCpyFrameNum(%d)\n", realCpyFrameNum);
3733                                                         }
3734
3735                                                         tmp = 0;
3736                                                         pInfo->tagV2Info.bSyncLyricsMarked = true;
3737                                                 } else if (strncmp((char *)CompTmp, "USLT", 4) == 0 && pInfo->tagV2Info.bUnsyncLyricsMarked == false) {
3738                                                         if (realCpyFrameNum > 3) {
3739                                                                 realCpyFrameNum -= 3;
3740                                                                 tmp = 3;
3741
3742                                                                 if (textEncodingType == AV_ID3V2_UTF16 || textEncodingType == AV_ID3V2_UTF16_BE) {
3743                                                                         while ((NEWLINE_OF_UTF16(pExtContent + tmp) || NEWLINE_OF_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 4) {
3744                                                                                 realCpyFrameNum -= 4;
3745                                                                                 tmp += 4;
3746                                                                         }
3747
3748                                                                         if ((IS_ENCODEDBY_UTF16(pExtContent + tmp) || IS_ENCODEDBY_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 2) {
3749                                                                                 realCpyFrameNum -= 2;
3750                                                                                 tmp += 2;
3751                                                                                 textEncodingType = AV_ID3V2_UTF16;
3752                                                                         } else {
3753                                                                                 debug_msg(RELEASE, "pInfo->pUnsyncLyrics Never Get Here!!\n");
3754                                                                         }
3755                                                                 } else if (textEncodingType == AV_ID3V2_UTF8) {
3756                                                                         while (pExtContent[tmp] < 0x20 && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
3757                                                                                 realCpyFrameNum--;
3758                                                                                 tmp++;
3759                                                                         }
3760                                                                         textEncodingType = AV_ID3V2_UTF8;
3761                                                                 } else {
3762                                                                         while (pExtContent[tmp] < 0x20 && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
3763                                                                                 realCpyFrameNum--;
3764                                                                                 tmp++;
3765                                                                         }
3766                                                                         textEncodingType = AV_ID3V2_ISO_8859;
3767                                                                 }
3768
3769                                                                 debug_msg(RELEASE, "tmp(%d) textEncodingType(%d), realCpyFrameNum(%d)\n", tmp, textEncodingType, realCpyFrameNum);
3770
3771                                                                 if (textEncodingType == AV_ID3V2_UTF8) {
3772                                                                         pInfo->pUnsyncLyrics = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3773
3774                                                                         if (pInfo->pUnsyncLyrics != NULL) {
3775                                                                                 memset(pInfo->pUnsyncLyrics, 0, (realCpyFrameNum + 2));
3776                                                                                 memcpy(pInfo->pUnsyncLyrics, pExtContent + tmp, realCpyFrameNum);
3777                                                                                 pInfo->pUnsyncLyrics[realCpyFrameNum] = '\0';
3778                                                                                 /*string copy with '\0'*/
3779                                                                                 pInfo->unsynclyricsLen = realCpyFrameNum;
3780                                                                                 _STRNCPY_EX(pInfo->pUnsyncLyrics, pExtContent, pInfo->unsynclyricsLen);
3781                                                                         } else {
3782                                                                                 debug_error(DEBUG, "out of memoryu for SyncLyrics\n");
3783                                                                         }
3784                                                                 } else {
3785                                                                         pInfo->pUnsyncLyrics = mmfile_string_convert((const char *)&pExtContent[tmp], realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->unsynclyricsLen);
3786                                                                 }
3787                                                         } else {
3788                                                                 debug_msg(RELEASE, "Description info too small to parse realCpyFrameNum(%d)\n", realCpyFrameNum);
3789                                                         }
3790
3791                                                         tmp = 0;
3792
3793                                                         debug_msg(RELEASE, "pInfo->pUnsyncLyrics returned = (%s), pInfo->unsynclyricsLen(%d)\n", pInfo->pUnsyncLyrics, pInfo->unsynclyricsLen);
3794                                                         pInfo->tagV2Info.bDescriptionMarked = true;
3795                                                 } else if (strncmp((char *)CompTmp, "TCON", 4) == 0 && pInfo->tagV2Info.bGenreMarked == false) {
3796                                                         if (textEncodingType == AV_ID3V2_UTF8) {
3797                                                                 pInfo->pGenre = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3798                                                                 if (pInfo->pGenre) {
3799                                                                         memcpy(pInfo->pGenre, pExtContent, realCpyFrameNum);
3800                                                                         pInfo->pGenre[realCpyFrameNum] = '\0';
3801                                                                         /*string copy with '\0'*/
3802                                                                         pInfo->genreLen = realCpyFrameNum;
3803                                                                         _STRNCPY_EX(pInfo->pGenre, pExtContent, pInfo->genreLen);
3804                                                                 }
3805                                                         } else {
3806                                                                 pInfo->pGenre = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->genreLen);
3807                                                         }
3808
3809                                                         debug_msg(RELEASE, "pInfo->pGenre returned = (%s), pInfo->genreLen(%d)\n", pInfo->pGenre, pInfo->genreLen);
3810
3811                                                         if ((pInfo->pGenre != NULL) && (pInfo->genreLen > 0)) {
3812                                                                 bool ret = FALSE;
3813                                                                 int int_genre = -1;
3814
3815                                                                 ret = is_numeric(pInfo->pGenre, pInfo->genreLen);
3816
3817                                                                 if (ret == TRUE) {
3818                                                                         ret = safe_atoi(pInfo->pGenre, &int_genre);
3819                                                                         if (ret == TRUE) {
3820                                                                                 debug_msg(RELEASE, "genre information is inteager [%d]\n", int_genre);
3821
3822                                                                                 /*Change int to string */
3823                                                                                 if ((0 <= int_genre) && (int_genre < GENRE_COUNT - 1)) {
3824                                                                                         /*save genreinfo like "(123)". mm_file_id3tag_restore_content_info convert it to string*/
3825                                                                                         char tmp_genre[6] = {0, };      /*ex. "(123)+NULL"*/
3826                                                                                         int tmp_genre_len = 0;
3827
3828                                                                                         memset(tmp_genre, 0, 6);
3829                                                                                         snprintf(tmp_genre, sizeof(tmp_genre), "(%d)", int_genre);
3830
3831                                                                                         tmp_genre_len = strlen(tmp_genre);
3832                                                                                         if (tmp_genre_len > 0) {
3833                                                                                                 if (pInfo->pGenre) _FREE_EX(pInfo->pGenre);
3834                                                                                                 pInfo->pGenre = mmfile_malloc(sizeof(char) * (tmp_genre_len + 1));
3835                                                                                                 if (pInfo->pGenre) {
3836                                                                                                         SAFE_STRLCPY(pInfo->pGenre, tmp_genre, tmp_genre_len + 1);
3837                                                                                                 }
3838                                                                                         }
3839                                                                                 }
3840                                                                         } else {
3841                                                                                 debug_msg(RELEASE, "genre information is wrong inteager [%s]\n", pInfo->pGenre);
3842                                                                         }
3843                                                                 }
3844                                                         }
3845
3846                                                         pInfo->tagV2Info.bGenreMarked = true;
3847                                                 } else if (strncmp((char *)CompTmp, "TRCK", 4) == 0 && pInfo->tagV2Info.bTrackNumMarked == false) {
3848                                                         if (textEncodingType == AV_ID3V2_UTF8) {
3849                                                                 pInfo->pTrackNum = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3850                                                                 if (pInfo->pTrackNum != NULL) {
3851                                                                         memcpy(pInfo->pTrackNum, pExtContent, realCpyFrameNum);
3852                                                                         pInfo->pTrackNum[realCpyFrameNum] = '\0';
3853                                                                         /*string copy with '\0'*/
3854                                                                         pInfo->tracknumLen = realCpyFrameNum;
3855                                                                         _STRNCPY_EX(pInfo->pTrackNum, pExtContent, pInfo->tracknumLen);
3856                                                                 }
3857                                                         } else {
3858                                                                 pInfo->pTrackNum = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->tracknumLen);
3859                                                         }
3860
3861                                                         debug_msg(RELEASE, "pInfo->pTrackNum returned = (%s), pInfo->tracknumLen(%d)\n", pInfo->pTrackNum, pInfo->tracknumLen);
3862                                                         pInfo->tagV2Info.bTrackNumMarked = true;
3863                                                 } else if (strncmp((char *)CompTmp, "TENC", 4) == 0 && pInfo->tagV2Info.bEncByMarked == false) {
3864                                                         if (textEncodingType == AV_ID3V2_UTF8) {
3865                                                                 pInfo->pEncBy = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3866                                                                 if (pInfo->pEncBy != NULL) {
3867                                                                         memcpy(pInfo->pEncBy, pExtContent, realCpyFrameNum);
3868                                                                         pInfo->pEncBy[realCpyFrameNum] = '\0';
3869                                                                         /*string copy with '\0'*/
3870                                                                         pInfo->encbyLen = realCpyFrameNum;
3871                                                                         _STRNCPY_EX(pInfo->pEncBy, pExtContent, pInfo->encbyLen);
3872                                                                 }
3873                                                         } else {
3874                                                                 pInfo->pEncBy = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->encbyLen);
3875                                                         }
3876
3877                                                         debug_msg(RELEASE, "pInfo->pEncBy returned = (%s), pInfo->encbyLen(%d)\n", pInfo->pEncBy, pInfo->encbyLen);
3878                                                         pInfo->tagV2Info.bEncByMarked = true;
3879                                                 } else if (strncmp((char *)CompTmp, "WXXX", 4) == 0 && pInfo->tagV2Info.bURLMarked == false) {
3880                                                         if (textEncodingType == AV_ID3V2_UTF8) {
3881                                                                 pInfo->pURL = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3882                                                                 if (pInfo->pURL != NULL) {
3883                                                                         memcpy(pInfo->pURL, pExtContent, realCpyFrameNum);
3884                                                                         pInfo->pURL[realCpyFrameNum] = '\0';
3885                                                                         /*string copy with '\0'*/
3886                                                                         pInfo->urlLen = realCpyFrameNum;
3887                                                                         _STRNCPY_EX(pInfo->pURL, pExtContent, pInfo->urlLen);
3888                                                                 }
3889                                                         } else {
3890                                                                 pInfo->pURL = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->urlLen);
3891                                                         }
3892
3893                                                         debug_msg(RELEASE, "pInfo->pURL returned = (%s), pInfo->urlLen(%d)\n", pInfo->pURL, pInfo->urlLen);
3894                                                         pInfo->tagV2Info.bURLMarked = true;
3895                                                 } else if (strncmp((char *)CompTmp, "TCOP", 4) == 0 && pInfo->tagV2Info.bCopyRightMarked == false) {
3896                                                         if (textEncodingType == AV_ID3V2_UTF8) {
3897                                                                 pInfo->pCopyright = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3898                                                                 if (pInfo->pCopyright != NULL) {
3899                                                                         memcpy(pInfo->pCopyright, pExtContent, realCpyFrameNum);
3900                                                                         pInfo->pCopyright[realCpyFrameNum] = '\0';
3901                                                                         /*string copy with '\0'*/
3902                                                                         pInfo->copyrightLen = realCpyFrameNum;
3903                                                                         _STRNCPY_EX(pInfo->pCopyright, pExtContent, pInfo->copyrightLen);
3904                                                                 }
3905                                                         } else {
3906                                                                 pInfo->pCopyright = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->copyrightLen);
3907                                                         }
3908
3909                                                         debug_msg(RELEASE, "pInfo->pCopyright returned = (%s), pInfo->copyrightLen(%d)\n", pInfo->pCopyright, pInfo->copyrightLen);
3910                                                         pInfo->tagV2Info.bCopyRightMarked = true;
3911                                                 } else if (strncmp((char *)CompTmp, "TOPE", 4) == 0 && pInfo->tagV2Info.bOriginArtistMarked == false) {
3912                                                         if (textEncodingType == AV_ID3V2_UTF8) {
3913                                                                 pInfo->pOriginArtist = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3914                                                                 if (pInfo->pOriginArtist != NULL) {
3915                                                                         memcpy(pInfo->pOriginArtist, pExtContent, realCpyFrameNum);
3916                                                                         pInfo->pOriginArtist[realCpyFrameNum] = '\0';
3917                                                                         /*string copy with '\0'*/
3918                                                                         pInfo->originartistLen = realCpyFrameNum;
3919                                                                         _STRNCPY_EX(pInfo->pOriginArtist, pExtContent, pInfo->originartistLen);
3920                                                                 }
3921                                                         } else {
3922                                                                 pInfo->pOriginArtist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->originartistLen);
3923                                                         }
3924
3925                                                         debug_msg(RELEASE, "pInfo->pOriginArtist returned = (%s), pInfo->originartistLen(%d)\n", pInfo->pOriginArtist, pInfo->originartistLen);
3926                                                         pInfo->tagV2Info.bOriginArtistMarked = true;
3927                                                 } else if (strncmp((char *)CompTmp, "TCOM", 4) == 0 && pInfo->tagV2Info.bComposerMarked == false) {
3928                                                         if (textEncodingType == AV_ID3V2_UTF8) {
3929                                                                 pInfo->pComposer = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3930                                                                 if (pInfo->pComposer != NULL) {
3931                                                                         memcpy(pInfo->pComposer, pExtContent, realCpyFrameNum);
3932                                                                         pInfo->pComposer[realCpyFrameNum] = '\0';
3933                                                                         /*string copy with '\0'*/
3934                                                                         pInfo->composerLen = realCpyFrameNum;
3935                                                                         _STRNCPY_EX(pInfo->pComposer, pExtContent, pInfo->composerLen);
3936                                                                 }
3937                                                         } else {
3938                                                                 pInfo->pComposer = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->composerLen);
3939                                                         }
3940
3941                                                         debug_msg(RELEASE, "pInfo->pComposer returned = (%s), pInfo->originartistLen(%d)\n", pInfo->pComposer, pInfo->composerLen);
3942                                                         pInfo->tagV2Info.bComposerMarked = true;
3943                                                 } else if (strncmp((char *)CompTmp, "TDRC", 4) == 0 && pInfo->tagV2Info.bRecDateMarked == false) {      /*TYER(year) and TRDA are replaced by the TDRC */
3944                                                         if (textEncodingType == AV_ID3V2_UTF8) {
3945                                                                 pInfo->pRecDate = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3946                                                                 if (pInfo->pRecDate != NULL) {
3947                                                                         memcpy(pInfo->pRecDate, pExtContent, realCpyFrameNum);
3948                                                                         pInfo->pRecDate[realCpyFrameNum] = '\0';
3949                                                                         /*string copy with '\0'*/
3950                                                                         pInfo->recdateLen = realCpyFrameNum;
3951                                                                         _STRNCPY_EX(pInfo->pRecDate, pExtContent, pInfo->recdateLen);
3952                                                                 }
3953                                                         } else {
3954                                                                 pInfo->pRecDate = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->recdateLen);
3955                                                         }
3956
3957                                                         debug_msg(RELEASE, "pInfo->pRecDate returned = (%s), pInfo->recdateLen(%d)\n", pInfo->pRecDate, pInfo->recdateLen);
3958                                                         pInfo->tagV2Info.bRecDateMarked = true;
3959                                                 } else if (strncmp((char *)CompTmp, "TIT1", 4) == 0 && pInfo->tagV2Info.bContentGroupMarked == false) {
3960                                                         if (textEncodingType == AV_ID3V2_UTF8) {
3961                                                                 pInfo->pContentGroup = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3962                                                                 if (pInfo->pContentGroup != NULL) {
3963                                                                         memcpy(pInfo->pContentGroup, pExtContent, realCpyFrameNum);
3964                                                                         pInfo->pContentGroup[realCpyFrameNum] = '\0';
3965                                                                         /*string copy with '\0'*/
3966                                                                         pInfo->contentGroupLen = realCpyFrameNum;
3967                                                                         _STRNCPY_EX(pInfo->pContentGroup, pExtContent, pInfo->contentGroupLen);
3968                                                                 }
3969                                                         } else {
3970                                                                 pInfo->pContentGroup = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->contentGroupLen);
3971                                                         }
3972
3973                                                         debug_msg(RELEASE, "pInfo->pContentGroup returned = (%s), pInfo->contentGroupLen(%d)\n", pInfo->pContentGroup, pInfo->contentGroupLen);
3974                                                         pInfo->tagV2Info.bContentGroupMarked = true;
3975                                                 } else if (strncmp((char *)CompTmp, "APIC", 4) == 0 && pInfo->tagV2Info.bImageMarked == false && realCpyFrameNum <= 2000000) {
3976                                                         if (pExtContent[0] != '\0') {
3977                                                                 for (inx = 0; inx < MP3_ID3_IMAGE_MIME_TYPE_MAX_LENGTH - 1; inx++)
3978                                                                         pInfo->imageInfo.imageMIMEType[inx] = '\0';/*ini mimetype variable */
3979
3980                                                                 while ((checkImgMimeTypeMax < MP3_ID3_IMAGE_MIME_TYPE_MAX_LENGTH - 1) && pExtContent[checkImgMimeTypeMax] != '\0') {
3981                                                                         pInfo->imageInfo.imageMIMEType[checkImgMimeTypeMax] = pExtContent[checkImgMimeTypeMax];
3982                                                                         checkImgMimeTypeMax++;
3983                                                                 }
3984                                                                 pInfo->imageInfo.imgMimetypeLen = checkImgMimeTypeMax;
3985                                                         } else {
3986                                                                 pInfo->imageInfo.imgMimetypeLen = 0;
3987                                                         }
3988
3989                                                         imgstartOffset += checkImgMimeTypeMax;
3990
3991                                                         if (strncmp(pInfo->imageInfo.imageMIMEType, MIME_PRFIX, strlen(MIME_PRFIX)) != 0) {
3992                                                                 pInfo->imageInfo.imgMimetypeLen = 0;
3993                                                                 debug_error(DEBUG, "APIC NOT VALID");
3994                                                                 continue;
3995                                                         }
3996
3997                                                         if ((pExtContent[imgstartOffset] == '\0') && (realCpyFrameNum - imgstartOffset > 0)) {
3998                                                                 imgstartOffset++;/*endofMIME(1byte) */
3999
4000                                                                 if (pExtContent[imgstartOffset] < AV_ID3V2_PICTURE_TYPE_MAX) {
4001                                                                         pInfo->imageInfo.pictureType = pExtContent[imgstartOffset];
4002                                                                 }
4003                                                                 imgstartOffset++;/*PictureType(1byte) */
4004
4005                                                                 if (pExtContent[imgstartOffset] != 0x0) {
4006                                                                         int cur_pos = 0;
4007                                                                         int dis_len = 0;
4008                                                                         int new_dis_len = 0;
4009                                                                         char *tmp_desc = NULL;
4010
4011                                                                         while (1) {
4012                                                                                 if (pExtContent[imgstartOffset + cur_pos] == '\0') {
4013                                                                                         if (realCpyFrameNum < imgstartOffset + cur_pos) {
4014                                                                                                 debug_error(DEBUG, "End of APIC Tag %d %d %d\n", realCpyFrameNum, imgstartOffset, cur_pos);
4015                                                                                                 break;
4016                                                                                         }
4017                                                                                         /*check end of image description*/
4018                                                                                         if ((pExtContent[imgstartOffset + cur_pos + 1] == gTagJPEGHeader[0]) ||
4019                                                                                             (pExtContent[imgstartOffset + cur_pos + 1] == gTagPNGHeader[0])) {
4020                                                                                                 debug_msg(RELEASE, "length of description (%d)", cur_pos);
4021                                                                                                 break;
4022                                                                                         }
4023                                                                                 }
4024                                                                                 cur_pos++;
4025                                                                         }
4026
4027                                                                         dis_len = cur_pos + 1;
4028
4029                                                                         tmp_desc = mmfile_malloc(sizeof(char) * dis_len);
4030
4031                                                                         if (tmp_desc != NULL) {
4032                                                                                 memcpy(tmp_desc, pExtContent + imgstartOffset, dis_len);
4033                                                                                 debug_msg(DEBUG, "tmp_desc %s\n", tmp_desc);
4034
4035                                                                                 /*convert description*/
4036                                                                                 pInfo->imageInfo.imageDescription = mmfile_string_convert(tmp_desc, dis_len, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&new_dis_len);
4037                                                                                 debug_msg(DEBUG, "new_desc %s(%d)\n", pInfo->imageInfo.imageDescription, new_dis_len);
4038                                                                                 mmfile_free(tmp_desc);
4039
4040                                                                                 pInfo->imageInfo.imgDesLen = new_dis_len; /**/
4041                                                                         }
4042
4043                                                                         imgstartOffset += cur_pos;
4044                                                                 } else {
4045                                                                         pInfo->imageInfo.imgDesLen = 0;
4046                                                                 }
4047
4048                                                                 if ((pExtContent[imgstartOffset] == '\0') && (realCpyFrameNum - imgstartOffset > 0)) {
4049                                                                         imgstartOffset++; /* endofDesceriptionType(1byte) */
4050
4051                                                                         while (pExtContent[imgstartOffset] == '\0') {   /*some content has useless '\0' in front of picture data */
4052                                                                                 imgstartOffset++;
4053                                                                         }
4054
4055                                                                         debug_msg(RELEASE, "after scaning imgDescription imgstartOffset(%d) value!\n", imgstartOffset);
4056
4057                                                                         if (realCpyFrameNum - imgstartOffset > 0) {
4058                                                                                 pInfo->imageInfo.imageLen = realCpyFrameNum - imgstartOffset;
4059                                                                                 pInfo->imageInfo.pImageBuf = mmfile_malloc(pInfo->imageInfo.imageLen + 1);
4060
4061                                                                                 if (pInfo->imageInfo.pImageBuf != NULL) {
4062                                                                                         memcpy(pInfo->imageInfo.pImageBuf, pExtContent + imgstartOffset, pInfo->imageInfo.imageLen);
4063                                                                                         pInfo->imageInfo.pImageBuf[pInfo->imageInfo.imageLen] = 0;
4064                                                                                 }
4065
4066                                                                                 if (IS_INCLUDE_URL(pInfo->imageInfo.imageMIMEType))
4067                                                                                         pInfo->imageInfo.bURLInfo = true; /*if mimetype is "-->", image date has an URL */
4068                                                                         } else {
4069                                                                                 debug_msg(RELEASE, "No APIC image!! realCpyFrameNum(%d) - imgstartOffset(%d)\n", realCpyFrameNum, imgstartOffset);
4070                                                                         }
4071                                                                 }
4072                                                         }
4073
4074                                                         checkImgMimeTypeMax = 0;
4075                                                         inx = 0;
4076                                                         imgstartOffset = 0;
4077                                                         pInfo->tagV2Info.bImageMarked = true;
4078                                                 } else {
4079                                                         debug_msg(RELEASE, "CompTmp(%s) This Frame ID currently not Supports!!\n", CompTmp);
4080                                                 }
4081                                         }
4082
4083                                 } else {
4084                                         debug_msg(RELEASE, "mmf_file_id3tag_parse_v224: All of the pExtContent Values are NULL\n");
4085                                 }
4086
4087                         } else {
4088                                 curPos += purelyFramelen;
4089                                 if (purelyFramelen != 0)
4090                                         needToloopv2taglen = MP3_TAGv2_23_TXT_HEADER_LEN;
4091                         }
4092
4093                         if (pExtContent)        _FREE_EX(pExtContent);
4094                         memset(CompTmp, 0, 4);
4095                         if (curPos < taglen) {
4096                                 needToloopv2taglen -= oneFrameLen;
4097                                 v2numOfFrames++;
4098                         } else
4099                                 needToloopv2taglen = MP3_TAGv2_23_TXT_HEADER_LEN;
4100
4101                         oneFrameLen = 0;
4102                         encodingOffSet = 0;
4103                         realCpyFrameNum = 0;
4104                         textEncodingType = 0;
4105                         purelyFramelen = 0;
4106
4107                 }
4108         }
4109
4110         release_characterset_array(charset_array);
4111
4112         if (taglen)
4113                 return true;
4114         else
4115                 return false;
4116
4117 }
4118
4119 EXPORT_API
4120 void mm_file_id3tag_restore_content_info(AvFileContentInfo *pInfo)
4121 {
4122         char    *mpegAudioGenre = NULL/*, *tmpGenreForV1Tag = NULL*/;
4123         bool    bAdditionGenre = false /*, bMpegAudioFrame = false*/;
4124         int mpegAudioFileLen = 0, idv2IntGenre = 148/*, tmpinx = 0, tmpinx2=0*/;
4125         unsigned char genre = pInfo->genre;
4126
4127         /* for Genre Info */
4128         if (pInfo->tagV2Info.bGenreMarked == false) {
4129                 if (pInfo->bV1tagFound == true) {
4130                         debug_msg(RELEASE, "Genre: %d\n", genre);
4131
4132                         if (genre > 147)
4133                                 genre = 148;
4134
4135                         if (MpegAudio_Genre[genre] != NULL) {
4136                                 pInfo->genreLen = strlen(MpegAudio_Genre[genre]);
4137                                 if (pInfo->genreLen > 0) {
4138                                         /* Give space for NULL character. Hence added "+1" */
4139                                         pInfo->pGenre = mmfile_malloc(sizeof(char) * (pInfo->genreLen + 1));
4140                                         if (pInfo->pGenre) {
4141                                                 SAFE_STRLCPY(pInfo->pGenre, MpegAudio_Genre[genre], pInfo->genreLen + 1);
4142                                         }
4143                                 }
4144                         }
4145                 } else {
4146                         debug_msg(RELEASE, "Genre was not Found.\n");
4147                 }
4148         } else if (pInfo->tagV2Info.bGenreMarked == true) {
4149                 if (pInfo->genreLen && pInfo->tagV2Info.bGenreUTF16) {
4150                         pInfo->pGenre[pInfo->genreLen + 1] = '\0';
4151                         mpegAudioGenre = mmfile_malloc(sizeof(char) * (pInfo->genreLen * AV_WM_LOCALCODE_SIZE_MAX + 1));
4152                 } else {
4153                         debug_msg(RELEASE, "pInfo->genreLen size is Zero Or not UTF16 code! genreLen[%d] genre[%s]\n", pInfo->genreLen, pInfo->pGenre);
4154
4155                         if (pInfo->pGenre) {
4156                                 pInfo->genreLen = strlen(pInfo->pGenre);
4157                                 mpegAudioGenre = mmfile_malloc(sizeof(char) * (pInfo->genreLen + 1));
4158                                 if (mpegAudioGenre != NULL) {
4159                                         SAFE_STRLCPY(mpegAudioGenre, pInfo->pGenre, pInfo->genreLen + 1);
4160                                 }
4161                         } else {
4162                                 pInfo->genreLen = 0;
4163                         }
4164                 }
4165
4166                 if (pInfo->pGenre) _FREE_EX(pInfo->pGenre);
4167
4168                 /*tmpinx = 0;*/
4169                 if (mpegAudioGenre != NULL) {
4170                         /**
4171                          *Genre number
4172                          * (XXX)        XXX is 0 - 148
4173                          */
4174                         pInfo->genreLen = strlen(mpegAudioGenre);
4175                         if (pInfo->genreLen >= 3 &&
4176                             mpegAudioGenre[0] == '(' && mpegAudioGenre[pInfo->genreLen - 1] == ')') {
4177                                 bAdditionGenre = true;
4178                                 for (mpegAudioFileLen = 1; mpegAudioFileLen <= pInfo->genreLen - 2; mpegAudioFileLen++) {
4179                                         if (mpegAudioGenre[mpegAudioFileLen] < '0' || mpegAudioGenre[mpegAudioFileLen] > '9') {
4180                                                 bAdditionGenre = false;
4181                                                 break;
4182                                         }
4183                                 }
4184                         }
4185
4186                         if (bAdditionGenre == true) {
4187                                 idv2IntGenre = atoi(mpegAudioGenre + 1);
4188
4189                                 if (idv2IntGenre > 147 || idv2IntGenre < 0)
4190                                         idv2IntGenre = 148;
4191
4192                                 if (MpegAudio_Genre[idv2IntGenre] != NULL) {
4193                                         pInfo->genreLen = strlen(MpegAudio_Genre[idv2IntGenre]);
4194                                         if (pInfo->genreLen > 0) {
4195                                                 /* Give space for NULL character. Hence added "+1" */
4196                                                 pInfo->pGenre = mmfile_malloc(sizeof(char) * (pInfo->genreLen + 1));
4197                                                 if (pInfo->pGenre) {
4198                                                         SAFE_STRLCPY(pInfo->pGenre, MpegAudio_Genre[idv2IntGenre], pInfo->genreLen + 1);
4199                                                 }
4200                                         }
4201                                 }
4202                                 debug_msg(RELEASE, "pInfo->pGenre = %s\n", pInfo->pGenre);
4203                         } else if (bAdditionGenre == false && pInfo->genreLen > 0) {
4204                                 /**
4205                                  * Genre string.
4206                                  */
4207
4208                                 /* Give space for NULL character. Hence added "+1" */
4209                                 pInfo->pGenre = mmfile_malloc(sizeof(char) * (pInfo->genreLen + 1));
4210                                 if (pInfo->pGenre) {
4211                                         SAFE_STRLCPY(pInfo->pGenre, mpegAudioGenre, pInfo->genreLen + 1);
4212                                 }
4213                                 debug_msg(RELEASE, "pInfo->pGenre = %s, pInfo->genreLen = %d\n", pInfo->pGenre, pInfo->genreLen);
4214                         } else {
4215                                 debug_msg(RELEASE, "Failed to \"(...)\" value to genre = %s\n", pInfo->pGenre);
4216                         }
4217                 } else {
4218                         debug_msg(RELEASE, "mpegAudioGenre = %s\n", mpegAudioGenre);
4219                 }
4220                 if (mpegAudioGenre)
4221                         _FREE_EX(mpegAudioGenre);
4222
4223         } else {
4224                 debug_msg(RELEASE, "Neither ID3 v1 nor v2 info doesn't have Genre Info.\n");
4225         }
4226
4227 }
4228
4229 void mm_file_free_synclyrics_list(GList *synclyrics_list)
4230 {
4231         int list_len = 0;
4232         int idx = 0;
4233         AvSynclyricsInfo *synclyrics_info = NULL;
4234
4235         if (synclyrics_list == NULL) {
4236                 return;
4237         }
4238
4239         list_len = g_list_length(synclyrics_list);
4240         for (idx = 0; idx < list_len; idx++) {
4241                 synclyrics_info = g_list_nth_data(synclyrics_list, idx);
4242
4243                 if (synclyrics_info != NULL) {
4244                         mmfile_free(synclyrics_info->lyric_info);
4245                         mmfile_free(synclyrics_info);
4246                 }
4247         }
4248
4249         if (synclyrics_list != NULL) {
4250                 g_list_free(synclyrics_list);
4251                 synclyrics_list = NULL;
4252         }
4253
4254         return;
4255 }
4256