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