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