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