Fix coverity issue (memory leak)
[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 /*
807         Samsung Metadata
808         0: None-mode
809         1: 360 normal
810         2: 360 timelapse
811         3: 180 normal
812         4: 180 timelapse
813         5: 360 looping mode
814         6: 180 looping mode
815         7: 360 slowmotion mode
816         8: 180 slowmotion mode
817 */
818         if (smtaTag.saut[0] == 's'
819             && smtaTag.saut[1] == 'a'
820             && smtaTag.saut[2] == 'u'
821             && smtaTag.saut[3] == 't') {
822                 if (smtaTag.value == 0x01) {
823                         debug_msg(RELEASE, "This has saut tag and valid value");
824                         formatContext->smta = 1;
825                 } else if (smtaTag.value == 0x02) {
826                         debug_msg(RELEASE, "This has saut tag and valid value");
827                         formatContext->smta = 2;
828                 } else {
829                         debug_error(DEBUG, "This has saut tag but invalid value");
830                         goto exception;
831                 }
832         } else {
833                 debug_error(DEBUG, "This hasn't saut tag and valid value");
834                 goto exception;
835         }
836
837         return MMFILE_UTIL_SUCCESS;
838
839 exception:
840         mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
841
842         return MMFILE_UTIL_FAIL;
843 }
844
845 static int GetSA3DInfoFromMP4ATagBox(MMFileFormatContext *formatContext, MMFileIOHandle *fp, MMFILE_MP4_BASIC_BOX_HEADER *basic_header)
846 {
847         if (!formatContext || !fp || !basic_header) {
848                 debug_error(DEBUG, "invalid param\n");
849                 return MMFILE_UTIL_FAIL;
850         }
851
852         unsigned char *buffer;
853         int readed = 0;
854         bool is_SA3D_present = false;
855         unsigned int i = 0;
856         MMFILE_MP4A_SA3D_TAGBOX sa3dTag = {0, };
857
858         formatContext->ambisonicType = MMFILE_AMBISONIC_TYPE_UNKNOWN;
859         formatContext->ambisonicOrder = MMFILE_AMBISONIC_ORDER_UNKNOWN;
860         formatContext->ambisonicFormat = MMFILE_AMBISONIC_FORMAT_UNKNOWN;
861
862         mmfile_seek(fp, basic_header->start_offset, SEEK_SET);
863
864         buffer = calloc(basic_header->size + 1, sizeof(unsigned char));
865         if (!buffer) {
866                 debug_error(DEBUG, "calloc failed ");
867                 goto exception;
868         }
869
870         readed = mmfile_read(fp, buffer, basic_header->size);
871         if (readed != (int)basic_header->size) {
872                 debug_error(DEBUG, "read mp4a box failed\n");
873                 goto exception;
874         }
875
876         for (i = 0; i + 3 < basic_header->size; ++i)
877                 if (buffer[i] == 'S' && buffer[i + 1] == 'A' && buffer[i + 2] == '3' && buffer[i + 3] == 'D') {
878                         debug_warning(DEBUG, "SA3D data found at offset %d bytes\n", i);
879                         is_SA3D_present = true;
880                         break;
881                 }
882
883         if (!is_SA3D_present) {
884                 debug_warning(DEBUG, "No SA3D box found");
885                 goto exception;
886         }
887
888         mmfile_seek(fp, basic_header->start_offset + i + 4, SEEK_SET);
889
890         readed = mmfile_read(fp, (unsigned char *)&sa3dTag, sizeof(MMFILE_MP4A_SA3D_TAGBOX));
891         if (readed != sizeof(MMFILE_MP4A_SA3D_TAGBOX)) {
892                 debug_error(DEBUG, "read SA3D tag header fail\n");
893                 goto exception;
894         }
895
896         sa3dTag.ambisonic_order = mmfile_io_be_uint32(sa3dTag.ambisonic_order);
897         sa3dTag.num_channels = mmfile_io_be_uint32(sa3dTag.num_channels);
898         for (i = 0; i < sa3dTag.num_channels; ++i)
899                 sa3dTag.channel_map[i] = mmfile_io_be_uint32(sa3dTag.channel_map[i]);
900
901         debug_msg(RELEASE, "sa3dTag.version = %d", sa3dTag.version);
902         debug_msg(RELEASE, "sa3dTag.ambisonic_type = %d", sa3dTag.ambisonic_type);
903         debug_msg(RELEASE, "sa3dTag.ambisonic_order = %d", sa3dTag.ambisonic_order);
904         debug_msg(RELEASE, "sa3dTag.ambisonic_channel_ordering = %d", sa3dTag.ambisonic_channel_ordering);
905         debug_msg(RELEASE, "sa3dTag.ambisonic_normalization = %d", sa3dTag.ambisonic_normalization);
906         debug_msg(RELEASE, "sa3dTag.num_channels = %d", sa3dTag.num_channels);
907         for (i = 0; i < sa3dTag.num_channels; ++i)
908                 debug_msg(RELEASE, "sa3dTag.channel_map[%d] = %d", i, sa3dTag.channel_map[i]);
909
910         if (sa3dTag.version != RFC_AMBISONIC_SA3DBOX_VERSION_SUPPORTED) {
911                 debug_error(DEBUG, "SA3D tag box version is unsupported\n");
912                 goto exception;
913         } else {
914                 if (sa3dTag.ambisonic_type == RFC_AMBISONIC_TYPE_PERIPHONIC)
915                         formatContext->ambisonicType = MMFILE_AMBISONIC_TYPE_PERIPHONIC;
916
917                 switch (sa3dTag.ambisonic_order) {
918                         case MMFILE_AMBISONIC_ORDER_FOA: {
919                                         if (sa3dTag.num_channels == 4) {
920                                                 formatContext->ambisonicOrder = MMFILE_AMBISONIC_ORDER_FOA;
921
922                                                 if ((sa3dTag.ambisonic_channel_ordering == RFC_AMBISONIC_CHANNEL_ORDERING_ACN) &&
923                                                                 (sa3dTag.ambisonic_normalization == RFC_AMBISONIC_NORMALIZATION_SN3D) &&
924                                                                 (sa3dTag.channel_map[0] == 0) &&
925                                                                 (sa3dTag.channel_map[1] == 1) &&
926                                                                 (sa3dTag.channel_map[2] == 2) &&
927                                                                 (sa3dTag.channel_map[3] == 3))
928                                                         formatContext->ambisonicFormat = MMFILE_AMBISONIC_FORMAT_AMBIX;
929
930                                                 if ((sa3dTag.ambisonic_channel_ordering == RFC_AMBISONIC_CHANNEL_ORDERING_FUMA) &&
931                                                                 (sa3dTag.ambisonic_normalization == RFC_AMBISONIC_NORMALIZATION_FUMA) &&
932                                                                 (sa3dTag.channel_map[0] == 0) &&
933                                                                 (sa3dTag.channel_map[1] == 3) &&
934                                                                 (sa3dTag.channel_map[2] == 1) &&
935                                                                 (sa3dTag.channel_map[3] == 2))
936                                                         formatContext->ambisonicFormat = MMFILE_AMBISONIC_FORMAT_AMB;
937                                         } else {
938                                                 debug_error(DEBUG, "Incorrect metadata: ambisonic order and channels number do not correspond\n");
939                                                 goto exception;
940                                         }
941
942                                         break;
943                                 }
944                         case MMFILE_AMBISONIC_ORDER_SOA: {
945                                         if (sa3dTag.num_channels == 9) {
946                                                 formatContext->ambisonicOrder = MMFILE_AMBISONIC_ORDER_SOA;
947
948                                                 if ((sa3dTag.ambisonic_channel_ordering == RFC_AMBISONIC_CHANNEL_ORDERING_ACN) &&
949                                                                 (sa3dTag.ambisonic_normalization == RFC_AMBISONIC_NORMALIZATION_SN3D) &&
950                                                                 (sa3dTag.channel_map[0] == 0) &&
951                                                                 (sa3dTag.channel_map[1] == 1) &&
952                                                                 (sa3dTag.channel_map[2] == 2) &&
953                                                                 (sa3dTag.channel_map[3] == 3) &&
954                                                                 (sa3dTag.channel_map[4] == 4) &&
955                                                                 (sa3dTag.channel_map[5] == 5) &&
956                                                                 (sa3dTag.channel_map[6] == 6) &&
957                                                                 (sa3dTag.channel_map[7] == 7) &&
958                                                                 (sa3dTag.channel_map[8] == 8))
959                                                         formatContext->ambisonicFormat = MMFILE_AMBISONIC_FORMAT_AMBIX;
960
961                                                 if ((sa3dTag.ambisonic_channel_ordering == RFC_AMBISONIC_CHANNEL_ORDERING_FUMA) &&
962                                                                 (sa3dTag.ambisonic_normalization == RFC_AMBISONIC_NORMALIZATION_FUMA) &&
963                                                                 (sa3dTag.channel_map[0] == 0) &&
964                                                                 (sa3dTag.channel_map[1] == 3) &&
965                                                                 (sa3dTag.channel_map[2] == 1) &&
966                                                                 (sa3dTag.channel_map[3] == 2) &&
967                                                                 (sa3dTag.channel_map[4] == 6) &&
968                                                                 (sa3dTag.channel_map[5] == 7) &&
969                                                                 (sa3dTag.channel_map[6] == 5) &&
970                                                                 (sa3dTag.channel_map[7] == 8) &&
971                                                                 (sa3dTag.channel_map[8] == 4))
972                                                         formatContext->ambisonicFormat = MMFILE_AMBISONIC_FORMAT_AMB;
973                                         } else {
974                                                 debug_error(DEBUG, "Incorrect metadata: ambisonic order and channels number do not correspond\n");
975                                                 goto exception;
976                                         }
977
978                                         break;
979                                 }
980
981                         case MMFILE_AMBISONIC_ORDER_TOA: {
982                                         if (sa3dTag.num_channels == 16) {
983                                                 formatContext->ambisonicOrder = MMFILE_AMBISONIC_ORDER_TOA;
984
985                                                 if ((sa3dTag.ambisonic_channel_ordering == RFC_AMBISONIC_CHANNEL_ORDERING_ACN) &&
986                                                                 (sa3dTag.ambisonic_normalization == RFC_AMBISONIC_NORMALIZATION_SN3D) &&
987                                                                 (sa3dTag.channel_map[0] == 0) &&
988                                                                 (sa3dTag.channel_map[1] == 1) &&
989                                                                 (sa3dTag.channel_map[2] == 2) &&
990                                                                 (sa3dTag.channel_map[3] == 3) &&
991                                                                 (sa3dTag.channel_map[4] == 4) &&
992                                                                 (sa3dTag.channel_map[5] == 5) &&
993                                                                 (sa3dTag.channel_map[6] == 6) &&
994                                                                 (sa3dTag.channel_map[7] == 7) &&
995                                                                 (sa3dTag.channel_map[8] == 8) &&
996                                                                 (sa3dTag.channel_map[9] == 9) &&
997                                                                 (sa3dTag.channel_map[10] == 10) &&
998                                                                 (sa3dTag.channel_map[11] == 11) &&
999                                                                 (sa3dTag.channel_map[12] == 12) &&
1000                                                                 (sa3dTag.channel_map[13] == 13) &&
1001                                                                 (sa3dTag.channel_map[14] == 14) &&
1002                                                                 (sa3dTag.channel_map[15] == 15))
1003                                                         formatContext->ambisonicFormat = MMFILE_AMBISONIC_FORMAT_AMBIX;
1004
1005                                                 if ((sa3dTag.ambisonic_channel_ordering == RFC_AMBISONIC_CHANNEL_ORDERING_FUMA) &&
1006                                                                 (sa3dTag.ambisonic_normalization == RFC_AMBISONIC_NORMALIZATION_FUMA) &&
1007                                                                 (sa3dTag.channel_map[0] == 0) &&
1008                                                                 (sa3dTag.channel_map[1] == 3) &&
1009                                                                 (sa3dTag.channel_map[2] == 1) &&
1010                                                                 (sa3dTag.channel_map[3] == 2) &&
1011                                                                 (sa3dTag.channel_map[4] == 6) &&
1012                                                                 (sa3dTag.channel_map[5] == 7) &&
1013                                                                 (sa3dTag.channel_map[6] == 5) &&
1014                                                                 (sa3dTag.channel_map[7] == 8) &&
1015                                                                 (sa3dTag.channel_map[8] == 4) &&
1016                                                                 (sa3dTag.channel_map[9] == 12) &&
1017                                                                 (sa3dTag.channel_map[10] == 13) &&
1018                                                                 (sa3dTag.channel_map[11] == 11) &&
1019                                                                 (sa3dTag.channel_map[12] == 14) &&
1020                                                                 (sa3dTag.channel_map[13] == 10) &&
1021                                                                 (sa3dTag.channel_map[14] == 15) &&
1022                                                                 (sa3dTag.channel_map[15] == 9))
1023                                                         formatContext->ambisonicFormat = MMFILE_AMBISONIC_FORMAT_AMB;
1024                                         } else {
1025                                                 debug_error(DEBUG, "Incorrect metadata: ambisonic order and channels number do not correspond\n");
1026                                                 goto exception;
1027                                         }
1028
1029                                         break;
1030                                 }
1031
1032                         default: {
1033                                         debug_warning(DEBUG, "Ambisonic order or format is not supported: ambix or amb formats up to 3rd order were expected.\n");
1034                                         goto exception;
1035                                         break;
1036                                 }
1037                 }
1038
1039                 debug_msg(RELEASE, "formatContext->ambisonic_type = %d", formatContext->ambisonicType);
1040                 debug_msg(RELEASE, "formatContext->ambisonic_order = %d", formatContext->ambisonicOrder);
1041                 debug_msg(RELEASE, "formatContext->ambisonic_format = %d", formatContext->ambisonicFormat);
1042         }
1043
1044         return MMFILE_UTIL_SUCCESS;
1045
1046 exception:
1047         mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
1048
1049         return MMFILE_UTIL_FAIL;
1050 }
1051
1052 static int ParseSt3dData(MMFileFormatContext *formatContext, MMFileIOHandle *fp, long long start_offset)
1053 {
1054         uint8_t stereo_mode = INVALID_UINT8_VALUE;
1055         unsigned int readed = 0;
1056
1057         mmfile_seek(fp, start_offset, SEEK_SET);
1058
1059         readed = mmfile_read(fp, (unsigned char *)&stereo_mode, sizeof(uint8_t));
1060         if (readed != sizeof(uint8_t)) {
1061                 debug_error(DEBUG, "read st3d tag header fail\n");
1062                 return MMFILE_UTIL_FAIL;
1063         }
1064
1065         formatContext->stereoModeV2 = stereo_mode;
1066
1067         return MMFILE_UTIL_SUCCESS;
1068 }
1069
1070 static int ParseSvhdData(MMFileFormatContext *formatContext, MMFileIOHandle *fp, long long start_offset, unsigned int box_size)
1071 {
1072         unsigned int readed = 0;
1073
1074         formatContext->metadataSourceV2 = (char *)calloc(1, box_size);
1075         if (!formatContext->metadataSourceV2) {
1076                 debug_error(DEBUG, "Calloc failed");
1077                 return MMFILE_UTIL_FAIL;
1078         }
1079
1080         mmfile_seek(fp, start_offset, SEEK_SET);
1081         readed = mmfile_read(fp, (unsigned char *)formatContext->metadataSourceV2, box_size);
1082         if (readed != box_size) {
1083                 debug_error(DEBUG, "read svhd tag header fail\n");
1084                 if (formatContext->metadataSourceV2)
1085                         free(formatContext->metadataSourceV2);
1086                 return MMFILE_UTIL_FAIL;
1087         }
1088
1089         return MMFILE_UTIL_SUCCESS;
1090 }
1091
1092 static int ParseProjData(MMFileFormatContext *formatContext, MMFileIOHandle *fp, long long start_offset)
1093 {
1094         unsigned int readed = 0;
1095         typedef struct proj_box_data_s {
1096                 uint32_t proj_type;
1097                 uint8_t version;
1098                 uint8_t flags[3];
1099         } __attribute__((aligned(1), packed)) proj_box_data;
1100
1101         typedef struct prhd_box_data_s {
1102                 uint32_t projection_pose_yaw;
1103                 uint32_t projection_pose_pitch;
1104                 uint32_t projection_pose_roll;
1105         } prhd_box_data;
1106
1107         typedef struct equi_box_data_s {
1108                 uint32_t projection_bounds_top;
1109                 uint32_t projection_bounds_bottom;
1110                 uint32_t projection_bounds_left;
1111                 uint32_t projection_bounds_right;
1112         } equi_box_data;
1113
1114         typedef struct cbmp_box_data_s {
1115                 uint32_t layout;
1116                 uint32_t padding;
1117         } cbmp_box_data;
1118
1119
1120         proj_box_data proj_data;
1121         proj_data.proj_type = INVALID_UINT_VALUE;
1122
1123         prhd_box_data prhd_data;
1124         prhd_data.projection_pose_yaw = INVALID_UINT_VALUE;
1125         prhd_data.projection_pose_pitch = INVALID_UINT_VALUE;
1126         prhd_data.projection_pose_roll = INVALID_UINT_VALUE;
1127
1128         equi_box_data equi_data;
1129         equi_data.projection_bounds_top = INVALID_UINT_VALUE;
1130         equi_data.projection_bounds_bottom = INVALID_UINT_VALUE;
1131         equi_data.projection_bounds_left = INVALID_UINT_VALUE;
1132         equi_data.projection_bounds_right = INVALID_UINT_VALUE;
1133
1134         cbmp_box_data cbmp_data;
1135         cbmp_data.layout = INVALID_UINT_VALUE;
1136         cbmp_data.padding = INVALID_UINT_VALUE;
1137
1138         mmfile_seek(fp, start_offset, SEEK_SET);
1139
1140         readed = mmfile_read(fp, (unsigned char *)&proj_data, sizeof(proj_box_data));
1141         if (readed != sizeof(proj_box_data)) {
1142                 debug_error(DEBUG, "read of proj box failed\n");
1143                 return MMFILE_UTIL_FAIL;
1144         }
1145
1146         formatContext->projTypeV2 = mmfile_io_be_uint32(proj_data.proj_type);
1147
1148         debug_error(DEBUG, "formatContext->projTypeV2 = %d\n", formatContext->projTypeV2);
1149         debug_error(DEBUG, "proj_data.version = %d\n", proj_data.version);
1150         debug_error(DEBUG, "proj_data.flags = %d\n", ((uint32_t)proj_data.flags[0] << 16) +
1151                         ((uint32_t)proj_data.flags[1] << 8) + (uint32_t)proj_data.flags[2]);
1152
1153         mmfile_seek(fp, sizeof(proj_box_data), SEEK_CUR);
1154         readed = mmfile_read(fp, (unsigned char *)&prhd_data, sizeof(prhd_box_data));
1155         if (readed != sizeof(prhd_box_data)) {
1156                 debug_error(DEBUG, "read of prhd box failed\n");
1157                 return MMFILE_UTIL_FAIL;
1158         }
1159
1160         formatContext->poseYawV2 = mmfile_io_be_uint32(prhd_data.projection_pose_yaw);
1161         formatContext->posePitchV2 = mmfile_io_be_uint32(prhd_data.projection_pose_pitch);
1162         formatContext->poseRollV2 = mmfile_io_be_uint32(prhd_data.projection_pose_roll);
1163
1164         debug_error(DEBUG, "formatContext->poseYawV2 = %d\n", formatContext->poseYawV2);
1165         debug_error(DEBUG, "formatContext->posePitchV2 = %d\n", formatContext->posePitchV2);
1166         debug_error(DEBUG, "formatContext->poseRollV2 = %d\n", formatContext->poseRollV2);
1167
1168         if (formatContext->projTypeV2 == PROJECTION_TYPE_EQUI) {
1169                 debug_msg(RELEASE, "Projection type is Equirectangular");
1170                 mmfile_seek(fp, 8, SEEK_CUR); /* 8 = 4 (for size) + 4 (fourcc) */
1171                 readed = mmfile_read(fp, (unsigned char *)&equi_data, sizeof(equi_box_data));
1172                 if (readed != sizeof(equi_box_data)) {
1173                         debug_error(DEBUG, "read of equi box failed\n");
1174                         return MMFILE_UTIL_FAIL;
1175                 }
1176
1177                 formatContext->equiBoundsTopV2 = mmfile_io_be_uint32(equi_data.projection_bounds_top);
1178                 formatContext->equiBoundsBottomV2 = mmfile_io_be_uint32(equi_data.projection_bounds_bottom);
1179                 formatContext->equiBoundsLeftV2 = mmfile_io_be_uint32(equi_data.projection_bounds_left);
1180                 formatContext->equiBoundsRightV2 = mmfile_io_be_uint32(equi_data.projection_bounds_right);
1181
1182                 debug_error(DEBUG, "formatContext->equiBoundsTopV2 = %d\n", formatContext->equiBoundsTopV2);
1183                 debug_error(DEBUG, "formatContext->equiBoundsBottomV2 = %d\n", formatContext->equiBoundsBottomV2);
1184                 debug_error(DEBUG, "formatContext->equiBoundsLeftV2 = %d\n", formatContext->equiBoundsLeftV2);
1185                 debug_error(DEBUG, "formatContext->equiBoundsRightV2 = %d\n", formatContext->equiBoundsRightV2);
1186
1187         } else if (formatContext->projTypeV2 == PROJECTION_TYPE_CBMP) {
1188                 debug_msg(RELEASE, "Projection type is Cubemap");
1189                 mmfile_seek(fp, 8, SEEK_CUR); /* 8 = 4 (for size) + 4 (fourcc) */
1190                 readed = mmfile_read(fp, (unsigned char *)&cbmp_data, sizeof(cbmp_box_data));
1191                 if (readed != sizeof(cbmp_box_data)) {
1192                         debug_error(DEBUG, "read of cbmp box failed\n");
1193                         return MMFILE_UTIL_FAIL;
1194                 }
1195
1196                 formatContext->cbmpLayoutV2 = mmfile_io_be_uint32(cbmp_data.layout);
1197                 formatContext->cbmpPaddingV2 = mmfile_io_be_uint32(cbmp_data.padding);
1198
1199                 debug_error(DEBUG, "formatContext->cbmpLayoutV2 = %d\n", formatContext->cbmpLayoutV2);
1200                 debug_error(DEBUG, "formatContext->cbmpPaddingV2 = %d\n", formatContext->cbmpPaddingV2);
1201
1202         } else {
1203                 debug_msg(RELEASE, "Projection type is %d (unknown)", proj_data.proj_type);
1204                 return MMFILE_UTIL_FAIL;
1205         }
1206
1207         return MMFILE_UTIL_SUCCESS;
1208 }
1209
1210 static int GetVideoV2MetadataFromAvc1TagBox(MMFileFormatContext *formatContext, MMFileIOHandle *fp, MMFILE_MP4_BASIC_BOX_HEADER *basic_header)
1211 {
1212         if (!formatContext || !fp || !basic_header) {
1213                 debug_error(DEBUG, "invalid param\n");
1214                 return MMFILE_UTIL_FAIL;
1215         }
1216
1217         unsigned char *buffer;
1218         int readed = 0;
1219         unsigned int i = 0;
1220
1221         formatContext->stereoModeV2 = INVALID_UINT_VALUE;
1222         formatContext->metadataSourceV2 = NULL;
1223         formatContext->projTypeV2 = INVALID_UINT_VALUE;
1224         formatContext->poseYawV2 = INVALID_UINT_VALUE;
1225         formatContext->posePitchV2 = INVALID_UINT_VALUE;
1226         formatContext->poseRollV2 = INVALID_UINT_VALUE;
1227         formatContext->cbmpLayoutV2 = INVALID_UINT_VALUE;
1228         formatContext->cbmpPaddingV2 = INVALID_UINT_VALUE;
1229         formatContext->equiBoundsTopV2 = INVALID_UINT_VALUE;
1230         formatContext->equiBoundsBottomV2 = INVALID_UINT_VALUE;
1231         formatContext->equiBoundsLeftV2 = INVALID_UINT_VALUE;
1232         formatContext->equiBoundsRightV2 = INVALID_UINT_VALUE;
1233
1234         mmfile_seek(fp, basic_header->start_offset, SEEK_SET);
1235
1236         buffer = calloc(basic_header->size + 1, sizeof(unsigned char));
1237         if (!buffer) {
1238                 debug_error(DEBUG, "calloc failed ");
1239                 goto exception;
1240         }
1241
1242         readed = mmfile_read(fp, buffer, basic_header->size);
1243         if (readed != (int)basic_header->size) {
1244                 debug_error(DEBUG, "read st3d box failed\n");
1245                 goto exception;
1246         }
1247
1248         for (i = 0; i + 3 < basic_header->size; ++i) {
1249                 if ((buffer[i] == 's' && buffer[i + 1] == 't' && buffer[i + 2] == '3' && buffer[i + 3] == 'd') && (formatContext->stereoModeV2 == INVALID_UINT_VALUE)) {
1250                         debug_warning(DEBUG, "st3d data found at offset %lld\n", basic_header->start_offset + i);
1251                         ParseSt3dData(formatContext, fp, basic_header->start_offset + i + 4);
1252                         debug_msg(RELEASE, "formatContext->stereoModeV2 = %d", formatContext->stereoModeV2);
1253                 }
1254                 if (buffer[i] == 's' && buffer[i + 1] == 'v' && buffer[i + 2] == '3' && buffer[i + 3] == 'd') {
1255                         debug_warning(DEBUG, "sv3d data found at offset %lld\n", basic_header->start_offset + i);
1256                         formatContext->isSpherical = true;
1257                 }
1258                 if (buffer[i] == 's' && buffer[i + 1] == 'v' && buffer[i + 2] == 'h' && buffer[i + 3] == 'd') {
1259                         debug_warning(DEBUG, "svhd data found at offset %lld\n", basic_header->start_offset + i);
1260                         ParseSvhdData(formatContext, fp, basic_header->start_offset + i + 4, mmfile_io_be_uint32(*((uint32_t*)(buffer - 4 + i))));
1261                         debug_msg(RELEASE, "formatContext->metadataSourceV2 = %s (length = %zu)", formatContext->metadataSourceV2, strlen(formatContext->metadataSourceV2));
1262                 }
1263                 if (buffer[i] == 'p' && buffer[i + 1] == 'r' && buffer[i + 2] == 'o' && buffer[i + 3] == 'j') {
1264                         debug_warning(DEBUG, "proj data found at offset %lld\n", basic_header->start_offset + i);
1265                         ParseProjData(formatContext, fp, basic_header->start_offset + i + 4);
1266                 }
1267         }
1268
1269         return MMFILE_UTIL_SUCCESS;
1270
1271 exception:
1272         mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
1273
1274         return MMFILE_UTIL_FAIL;
1275 }
1276
1277 static int GetValueFromCDISTagBox(MMFileFormatContext *formatContext, MMFileIOHandle *fp, MMFILE_MP4_BASIC_BOX_HEADER *basic_header)
1278 {
1279         unsigned int value = 0;
1280         int readed = 0;
1281
1282         if (!formatContext || !fp || !basic_header) {
1283                 debug_error(DEBUG, "invalid param\n");
1284                 return MMFILE_UTIL_FAIL;
1285         }
1286
1287         readed = mmfile_read(fp, (unsigned char *)&value, sizeof(unsigned int));
1288         if (readed != sizeof(unsigned int)) {
1289                 debug_error(DEBUG, "read cdis tag header fail\n");
1290                 goto exception;
1291         }
1292
1293         value = mmfile_io_be_uint32(value);
1294
1295         debug_msg(RELEASE, "Value : 0x%x", value);
1296
1297         if (value == 0x01) {
1298                 debug_msg(RELEASE, "This has cdis tag and valid value");
1299                 formatContext->cdis = 1;
1300         } else {
1301                 debug_error(DEBUG, "This has cdis tag and but invalid value");
1302                 goto exception;
1303         }
1304
1305         return MMFILE_UTIL_SUCCESS;
1306
1307 exception:
1308         mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
1309
1310         return MMFILE_UTIL_FAIL;
1311 }
1312
1313 static int GetTagFromMetaBox(MMFileFormatContext *formatContext, MMFileIOHandle *fp, MMFILE_MP4_BASIC_BOX_HEADER *basic_header)
1314 {
1315         int readed = 0;
1316         MMFILE_MP4_BASIC_BOX_HEADER hdlrBoxHeader = {0, };
1317         MMFILE_MP4_BASIC_BOX_HEADER id3v2BoxHeader = {0, };
1318         MMFILE_3GP_ID3V2_BOX id3v2Box = {0, };
1319         AvFileContentInfo tagInfo = {0, };
1320         unsigned char tagVersion = 0;
1321         bool versionCheck = false;
1322         int id3v2Len = 0;
1323         unsigned int meta_version = 0;
1324         MMFILE_3GP_HANDLER_BOX hdlrBox = {0, };
1325         unsigned int encSize = 0;
1326         int id3_meta = 0;
1327 #ifdef ENABLE_ITUNES_META /* We don't support itunes meta now. so this is not defined yet */
1328         int iTunes_meta = 0;
1329 #endif
1330
1331         /* meta box */
1332         readed = mmfile_read(fp, (unsigned char *)&meta_version, 4);
1333         if (readed != 4) {
1334                 debug_error(DEBUG, "read meta box version\n");
1335                 goto exception;
1336         }
1337
1338         /* hdlr box */
1339         readed = mmfile_read(fp, (unsigned char *)&hdlrBoxHeader, MMFILE_MP4_BASIC_BOX_HEADER_LEN);
1340         if (readed != MMFILE_MP4_BASIC_BOX_HEADER_LEN) {
1341                 debug_error(DEBUG, "read hdlr box header\n");
1342                 goto exception;
1343         }
1344
1345         if (hdlrBoxHeader.type != FOURCC('h', 'd', 'l', 'r')) {
1346                 debug_warning(DEBUG, "meta type is not hdlr\n");
1347                 goto exception;
1348         }
1349
1350         hdlrBoxHeader.size = mmfile_io_be_uint32(hdlrBoxHeader.size);
1351         hdlrBoxHeader.type = mmfile_io_le_uint32(hdlrBoxHeader.type);
1352
1353         readed = mmfile_read(fp, (unsigned char *)&hdlrBox, MMFILE_3GP_HANDLER_BOX_LEN);
1354         if (readed != MMFILE_3GP_HANDLER_BOX_LEN) {
1355                 debug_error(DEBUG, "read hdlr box\n");
1356                 goto exception;
1357         }
1358
1359         hdlrBox.handler_type = mmfile_io_le_uint32(hdlrBox.handler_type);
1360
1361         /**
1362          * check tag type (ID3v2 or iTunes)
1363          */
1364         if (hdlrBox.handler_type == FOURCC('I', 'D', '3', '2')) {
1365                 debug_msg(RELEASE, "ID3v2 tag detected.\n");
1366
1367                 id3_meta = 1;
1368 #ifdef ENABLE_ITUNES_META
1369                 iTunes_meta = 0;
1370 #endif
1371         } else if (hdlrBox.handler_type == FOURCC('m', 'd', 'i', 'r') &&
1372                                 mmfile_io_le_uint32(hdlrBox.reserved[0]) == FOURCC('a', 'p', 'p', 'l')) {
1373
1374                 debug_msg(RELEASE, "Apple iTunes tag detected by mdir.\n");
1375
1376 #ifdef ENABLE_ITUNES_META
1377                 iTunes_meta = 1;
1378 #endif
1379         } else {
1380                 debug_warning(DEBUG, "unknown meta type. 4CC:[%c%c%c%c]\n", ((char *)&hdlrBox.handler_type)[0],
1381                                         ((char *)&hdlrBox.handler_type)[1],
1382                                         ((char *)&hdlrBox.handler_type)[2],
1383                                         ((char *)&hdlrBox.handler_type)[3]);
1384                 /*goto exception; */
1385         }
1386
1387 #ifdef ENABLE_ITUNES_META
1388         if (!id3_meta && !iTunes_meta) {
1389                 /*Check ilst.
1390                 APPLE meta data for iTunes reader = 'mdir.' so if handler type is 'mdir', this content may has itunes meta.
1391                 most of contents has 'mdir' + 'appl'. but some contents just has 'mdir'
1392                 but 'ilst' is meta for iTunes. so find 'ilst' is more correct to check if this contents has iTunes meta or not.*/
1393
1394                 const char *ilst_box = "ilst";
1395                 int buf_size = strlen(ilst_box);
1396
1397                 unsigned char read_buf[buf_size + 1];
1398                 memset(read_buf, 0x00, buf_size + 1);
1399
1400                 /* skip hdlr box */
1401                 mmfile_seek(fp, hdlrBoxHeader.size - MMFILE_MP4_BASIC_BOX_HEADER_LEN - MMFILE_3GP_HANDLER_BOX_LEN + 4, SEEK_CUR);       /*+4 is hdlr size field */
1402
1403                 readed = mmfile_read(fp, read_buf, buf_size);   /* to find 'ilst' */
1404                 if (readed != buf_size) {
1405                         debug_error(DEBUG, "read fail [%d]\n", readed);
1406                         goto exception;
1407                 }
1408
1409                 if (read_buf[0] == 'i' && read_buf[1] == 'l' && read_buf[2] == 's' && read_buf[3] == 't') {
1410                         debug_msg(RELEASE, "Apple iTunes tag detected by ilst.\n");
1411                         iTunes_meta = 1;
1412                 }
1413         }
1414 #endif
1415
1416 #ifdef ENABLE_ITUNES_META
1417         if (iTunes_meta) {
1418                 /**
1419                  * iTunes (Cover[?ovr] & Track[trkn] only extract!) + Genre/Artist : Added 2010.10.27,28
1420                  *
1421                  *  4cc   : 4byte
1422                  *        : 4byte       size
1423                  * 'data' : 4byte
1424                  *        : 4byte       type
1425                  *        : 4byte       unknown
1426                  */
1427 #define _ITUNES_READ_BUF_SZ             20
1428 #define _ITUNES_TRACK_NUM_SZ    4
1429 #define _ITUNES_GENRE_NUM_SZ    4
1430 #define _ITUNES_COVER_TYPE_JPEG 13
1431 #define _ITUNES_COVER_TYPE_PNG          14
1432
1433                 unsigned char read_buf[_ITUNES_READ_BUF_SZ];
1434                 int i = 0;
1435                 int cover_sz = 0, cover_type = 0, cover_found = 0;
1436                 /* int track_found = 0; */ /* , track_num = 0; */
1437                 /* int genre_found = 0; */ /* , genre_index = 0; */
1438                 /* int artist_found = 0; */ /* , artist_sz = 0; */
1439                 int limit = basic_header->size - hdlrBoxHeader.size;
1440                 long long cover_offset = 0; /*, track_offset =0, genre_offset = 0, artist_offset = 0; */
1441
1442                 /* 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++) { */
1443                 for (i = 0; (i < limit) && (cover_found == 0) ; i++) {
1444                         readed = mmfile_read(fp, read_buf, _ITUNES_READ_BUF_SZ);
1445                         if (readed != _ITUNES_READ_BUF_SZ)
1446                                 goto exception;
1447
1448                         /*ffmpeg extract artist, tracknum, genre and cover image. see mov_read_udta_string().
1449                         but ffmpeg does not support strange cover image.
1450                         only support covr type 0xd(JPEG), 0xe(PNG), 0x1b(BMP). but we support other type*/
1451 #if 0
1452                         /**
1453                          * Artist : Added 2010.10.28
1454                          */
1455                         if (artist_found == 0 &&
1456                             read_buf[0] == 0xa9 && read_buf[1] == 'A' && read_buf[2] == 'R' && read_buf[3] == 'T' &&
1457                             read_buf[8] == 'd' && read_buf[9] == 'a' && read_buf[10] == 't' && read_buf[11] == 'a') {
1458
1459                                 artist_found = 1;
1460                                 artist_offset = mmfile_tell(fp);
1461                                 artist_sz = mmfile_io_be_uint32(*(int *)(read_buf + 4)) - 16; /* atom len(4)+data(4)+atom verion(1)+flag(3)+null(4) = 16 */
1462
1463                                 debug_msg(RELEASE, "----------------------------------- artist found, offset=[%lld], size=[%d]\n", artist_offset, artist_sz);
1464                         }
1465
1466                         /**
1467                          * Track number
1468                          */
1469                         if (track_found == 0 &&
1470                             read_buf[0] == 't' && read_buf[1] == 'r' && read_buf[2] == 'k' && read_buf[3] == 'n' &&
1471                             read_buf[8] == 'd' && read_buf[9] == 'a' && read_buf[10] == 't' && read_buf[11] == 'a') {
1472
1473                                 track_found = 1;
1474                                 track_offset = mmfile_tell(fp);
1475
1476                                 debug_msg(RELEASE, "----------------------------------- Track found, offset=[%lld]\n", track_offset);
1477                         }
1478
1479                         /**
1480                          * Genre : Added 2010.10.27
1481                          */
1482                         /*ffmpeg extract genre but only (0xa9,'g','e','n'). see mov_read_udta_string()*/
1483                         if (genre_found == 0 &&
1484                             read_buf[0] == 'g' && read_buf[1] == 'n' && read_buf[2] == 'r' && read_buf[3] == 'e' &&
1485                             read_buf[8] == 'd' && read_buf[9] == 'a' && read_buf[10] == 't' && read_buf[11] == 'a') {
1486
1487                                 genre_found = 1;
1488                                 genre_offset = mmfile_tell(fp);
1489
1490                                 debug_msg(RELEASE, "----------------------------------- genre found, offset=[%lld]\n", genre_offset);
1491                         }
1492 #endif
1493
1494                         /**
1495                          * Cover image
1496                          */
1497
1498                         if (cover_found == 0 &&
1499                             read_buf[0] == 'c' && read_buf[1] == 'o' && read_buf[2] == 'v' && read_buf[3] == 'r' &&
1500                             read_buf[8] == 'd' && read_buf[9] == 'a' && read_buf[10] == 't' && read_buf[11] == 'a') {
1501
1502                                 cover_found = 1;
1503                                 cover_sz = mmfile_io_be_uint32(*(int *)(read_buf + 4)) - 12;
1504                                 cover_type = mmfile_io_be_uint32(*(int *)(read_buf + 12));
1505
1506                                 cover_offset = mmfile_tell(fp);
1507
1508                                 debug_msg(RELEASE, "----------------------------------- cover_found found,  offset=[%lld]\n", cover_offset);
1509                         }
1510
1511                         mmfile_seek(fp, -(_ITUNES_READ_BUF_SZ - 1), SEEK_CUR);  /*FIXME: poor search*/
1512                 } /*loop*/
1513
1514                 /*ffmpeg extract artist, tracknum, excep cover image. see mov_read_udta_string()*/
1515 #if 0
1516                 if (artist_found) {
1517                         if (artist_sz > 0) {
1518                                 mmfile_seek(fp, artist_offset, SEEK_SET);
1519
1520                                 if (formatContext->artist) {
1521                                         debug_msg(RELEASE, "----------------------------------- previous artist was [%s] \n", formatContext->artist);
1522                                         free(formatContext->artist);
1523                                 }
1524
1525                                 debug_msg(RELEASE, "----------------------------------- new artist will be allocated with size (len+1) [%d] \n", artist_sz + 1);
1526                                 formatContext->artist = mmfile_malloc(artist_sz + 1);
1527
1528                                 if (formatContext->artist) {
1529                                         readed = mmfile_read(fp, (unsigned char *)formatContext->artist, artist_sz);
1530                                         formatContext->artist[artist_sz] = '\0';
1531
1532                                         debug_msg(RELEASE, "----------------------------------- new artist is [%s] \n", formatContext->artist);
1533
1534                                         if (readed != artist_sz) {
1535                                                 debug_error(DEBUG, "failed to read. ret = %d, in = %d\n", readed, artist_sz);
1536                                                 mmfile_free(formatContext->artist);
1537                                         }
1538                                 }
1539                         }
1540                 }
1541
1542                 if (track_found) {
1543                         mmfile_seek(fp, track_offset, SEEK_SET);
1544                         readed = mmfile_read(fp, read_buf, _ITUNES_TRACK_NUM_SZ);
1545                         if (readed != _ITUNES_TRACK_NUM_SZ) {
1546                                 debug_error(DEBUG, "failed to read. ret = %d, in = %d\n", readed, _ITUNES_TRACK_NUM_SZ);
1547                         } else {
1548                                 track_num = mmfile_io_be_uint32(*(int *)read_buf);
1549                                 if (!formatContext->tagTrackNum) {
1550                                         memset(read_buf, 0x00, _ITUNES_READ_BUF_SZ);
1551                                         snprintf((char *)read_buf, sizeof(read_buf), "%d", track_num);
1552                                         formatContext->tagTrackNum = mmfile_strdup((const char *)read_buf);
1553                                 }
1554                         }
1555                 }
1556
1557                 if (genre_found) {
1558                         mmfile_seek(fp, genre_offset, SEEK_SET);
1559                         readed = mmfile_read(fp, read_buf, _ITUNES_GENRE_NUM_SZ);
1560                         if (readed != _ITUNES_GENRE_NUM_SZ) {
1561                                 debug_error(DEBUG, "failed to read. ret = %d, in = %d\n", readed, _ITUNES_GENRE_NUM_SZ);
1562                         } else {
1563                                 genre_index = mmfile_io_be_uint16(*(int *)read_buf);
1564                                 debug_msg(RELEASE, "genre index=[%d] \n", genre_index);
1565
1566                                 if (genre_index > 0 && genre_index < GENRE_COUNT)       {
1567                                         if (!formatContext->genre) {
1568                                                 memset(read_buf, 0x00, _ITUNES_READ_BUF_SZ);
1569                                                 snprintf((char *)read_buf, sizeof(read_buf), "%s", MpegAudio_Genre[genre_index - 1]);
1570                                                 debug_msg(RELEASE, "genre string=[%s] \n", read_buf);
1571                                                 formatContext->genre = mmfile_strdup((const char *)read_buf);
1572                                         }
1573                                 }
1574                         }
1575                 }
1576 #endif
1577
1578                 /*
1579                         1) below spec is in "iTunes Package Asset Specification 4.3" published by apple.
1580                         Music Cover Art Image Profile
1581                         - TIFF with ".tif" extension (32-bit uncompressed), JPEG with ".jpg" extension (quality unconstrained), or PNG with ".png" extension
1582                         - RGB (screen standard)
1583                         - Minimum size of 600 x 600 pixels
1584                         - Images must be at least 72 dpi
1585
1586                         2)I found below info from google.
1587                         cover image flag : JPEG (13, 0xd), PNG (14, 0xe)
1588
1589                         3)So, FIXME when cover image format is tif!
1590                 */
1591                 if (cover_found) {
1592                         if (cover_sz > 0) {
1593                                 mmfile_seek(fp, cover_offset, SEEK_SET);
1594
1595                                 formatContext->artwork = mmfile_malloc(cover_sz);
1596                                 formatContext->artworkSize = cover_sz;
1597                                 if (cover_type == _ITUNES_COVER_TYPE_JPEG) {
1598                                         formatContext->artworkMime = mmfile_strdup("image/jpeg");
1599                                 } else if (cover_type == _ITUNES_COVER_TYPE_PNG) {
1600                                         formatContext->artworkMime = mmfile_strdup("image/png");
1601                                         /*} else if (cover_type == _ITUNES_COVER_TYPE_TIF) {
1602                                                 formatContext->artworkMime = mmfile_strdup("image/tif");*/
1603                                 } else {
1604                                         debug_warning(DEBUG, "Not proper cover image type, but set to jpeg. cover_type[%d]", cover_type);
1605                                         formatContext->artworkMime = mmfile_strdup("image/jpeg");
1606                                 }
1607
1608                                 if (formatContext->artwork) {
1609                                         readed = mmfile_read(fp, formatContext->artwork, cover_sz);
1610                                         if (readed != cover_sz) {
1611                                                 debug_error(DEBUG, "failed to read. ret = %d, in = %d\n", readed, cover_sz);
1612                                                 mmfile_free(formatContext->artwork);
1613                                                 formatContext->artworkSize = 0;
1614                                                 mmfile_free(formatContext->artworkMime);
1615                                         }
1616                                 }
1617                         }
1618                 }
1619
1620                 /*reset seek position*/
1621                 mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
1622
1623                 return MMFILE_UTIL_SUCCESS;
1624
1625         } else
1626 #endif
1627                 if (id3_meta) {
1628                         /**
1629                          * ID3v2
1630                          */
1631                         /* skip hdlr box name */
1632                         mmfile_seek(fp, hdlrBoxHeader.size - MMFILE_MP4_BASIC_BOX_HEADER_LEN - MMFILE_3GP_HANDLER_BOX_LEN, SEEK_CUR);
1633
1634                         /* id3 tag box */
1635                         readed = mmfile_read(fp, (unsigned char *)&id3v2BoxHeader, MMFILE_MP4_BASIC_BOX_HEADER_LEN);
1636                         if (readed != MMFILE_MP4_BASIC_BOX_HEADER_LEN) {
1637                                 debug_error(DEBUG, "read id3v2 box header\n");
1638                                 goto exception;
1639                         }
1640
1641                         id3v2BoxHeader.size = mmfile_io_be_uint32(id3v2BoxHeader.size);
1642                         id3v2BoxHeader.type = mmfile_io_le_uint32(id3v2BoxHeader.type);
1643
1644                         if (id3v2BoxHeader.type != FOURCC('I', 'D', '3', '2')) {
1645                                 debug_warning(DEBUG, "meta type is not id3v2\n");
1646                                 goto exception;
1647                         }
1648
1649                         readed = mmfile_read(fp, (unsigned char *)&id3v2Box, MMFILE_3GP_ID3V2_BOX_LEN);
1650                         if (readed != MMFILE_3GP_ID3V2_BOX_LEN) {
1651                                 debug_error(DEBUG, "read id3v2 box\n");
1652                                 goto exception;
1653                         }
1654
1655                         id3v2Len = id3v2BoxHeader.size - MMFILE_MP4_BASIC_BOX_HEADER_LEN - MMFILE_3GP_ID3V2_BOX_LEN;
1656
1657                         id3v2Box.id3v2Data = mmfile_malloc(id3v2Len);
1658                         if (!id3v2Box.id3v2Data) {
1659                                 debug_error(DEBUG, "malloc id3tag data error\n");
1660                                 goto exception;
1661                         }
1662
1663                         readed = mmfile_read(fp, (unsigned char *)id3v2Box.id3v2Data, id3v2Len);
1664                         if (readed != id3v2Len) {
1665                                 debug_error(DEBUG, "read id3tag data error\n");
1666                                 goto exception;
1667                         }
1668
1669                         /* check id3v2 */
1670                         if (!IS_ID3V2_TAG(id3v2Box.id3v2Data)) {
1671                                 debug_error(DEBUG, "it is not id3tag\n");
1672                                 goto exception;
1673                         }
1674
1675                         if (id3v2Box.id3v2Data[3] == 0xFF ||  id3v2Box.id3v2Data[4] == 0xFF ||
1676                             id3v2Box.id3v2Data[6] >= 0x80 ||  id3v2Box.id3v2Data[7] >= 0x80 ||
1677                             id3v2Box.id3v2Data[8] >= 0x80 ||  id3v2Box.id3v2Data[9] >= 0x80) {
1678                                 debug_error(DEBUG, "it is not valid id3tag\n");
1679                                 goto exception;
1680                         }
1681
1682                         tagVersion = id3v2Box.id3v2Data[3];
1683                         if (tagVersion > 4) {
1684                                 debug_error(DEBUG, "tag vesion is too high\n");
1685                                 goto exception;
1686                         }
1687
1688                         encSize = mmfile_io_le_uint32((unsigned int)&id3v2Box.id3v2Data[6]);
1689                         tagInfo.tagV2Info.tagLen = MP3_TAGv2_HEADER_LEN;
1690                         tagInfo.tagV2Info.tagLen += (((encSize & 0x0000007F) >> 0) | ((encSize & 0x00007F00) >> 1) | ((encSize & 0x007F0000) >> 2) | ((encSize & 0x7F000000) >> 3));
1691                         tagInfo.tagV2Info.tagVersion = tagVersion;
1692                         tagInfo.fileLen = id3v2Len;
1693
1694                         /* set id3v2 data to formatContext */
1695                         switch (tagVersion) {
1696                         case 2: {
1697                                         versionCheck = mm_file_id3tag_parse_v222(&tagInfo, id3v2Box.id3v2Data);
1698                                         break;
1699                                 }
1700                         case 3: {
1701                                         versionCheck = mm_file_id3tag_parse_v223(&tagInfo, id3v2Box.id3v2Data);
1702                                         break;
1703                                 }
1704                         case 4: {
1705                                         versionCheck = mm_file_id3tag_parse_v224(&tagInfo, id3v2Box.id3v2Data);
1706                                         break;
1707                                 }
1708                         case 1:
1709                         default: {
1710                                         debug_error(DEBUG, "tag vesion is not support\n");
1711                                         versionCheck = false;
1712                                         break;
1713                                 }
1714                         }
1715
1716                         if (versionCheck == false) {
1717                                 debug_error(DEBUG, "tag parsing is fail\n");
1718                                 goto exception;
1719                         }
1720
1721                         formatContext->title = mmfile_strdup((const char *)tagInfo.pTitle);
1722                         formatContext->artist = mmfile_strdup((const char *)tagInfo.pArtist);
1723                         formatContext->author = mmfile_strdup((const char *)tagInfo.pAuthor);
1724                         formatContext->copyright = mmfile_strdup((const char *)tagInfo.pCopyright);
1725                         formatContext->comment = mmfile_strdup((const char *)tagInfo.pComment);
1726                         formatContext->album = mmfile_strdup((const char *)tagInfo.pAlbum);
1727                         formatContext->album_artist = mmfile_strdup((const char *)tagInfo.pAlbum_Artist);
1728                         formatContext->year = mmfile_strdup((const char *)tagInfo.pYear);
1729                         formatContext->genre = mmfile_strdup((const char *)tagInfo.pGenre);
1730                         formatContext->tagTrackNum = mmfile_strdup((const char *)tagInfo.pTrackNum);
1731                         formatContext->composer = mmfile_strdup((const char *)tagInfo.pComposer);
1732                         formatContext->classification = mmfile_strdup((const char *)tagInfo.pContentGroup);
1733                         formatContext->conductor = mmfile_strdup((const char *)tagInfo.pConductor);
1734
1735                         formatContext->artwork = mmfile_malloc(tagInfo.imageInfo.imageLen);
1736                         if ((tagInfo.imageInfo.imageLen > 0) && formatContext->artwork) {
1737                                 formatContext->artworkSize = tagInfo.imageInfo.imageLen;
1738                                 memcpy(formatContext->artwork, tagInfo.imageInfo.pImageBuf, tagInfo.imageInfo.imageLen);
1739                         }
1740
1741                         mm_file_free_AvFileContentInfo(&tagInfo);
1742                         mmfile_free(id3v2Box.id3v2Data);
1743
1744                         /*reset seek position*/
1745                         mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
1746
1747                         return MMFILE_UTIL_SUCCESS;
1748
1749                 }
1750
1751
1752 exception:
1753         mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
1754         mmfile_free(id3v2Box.id3v2Data);
1755         mm_file_free_AvFileContentInfo(&tagInfo);
1756
1757         return MMFILE_UTIL_FAIL;
1758 }
1759
1760 int mm_file_get_int_value_from_xml_string(const char* xml_str, const char* param_name, int* value)
1761 {
1762         char *value_start, *value_end, *endptr;
1763         const short value_length_max = 12;
1764         char init_view_ret[value_length_max];
1765         int value_length = 0;
1766
1767         if (!xml_str || !param_name || !strstr(xml_str, param_name)) {
1768                 debug_error(DEBUG, "error: incorrect or non-existing parameter\n");
1769                 return MMFILE_UTIL_FAIL;
1770         }
1771
1772         value_start = strstr(xml_str, param_name) + strlen(param_name);
1773         while ((value_start[0] == ' ') || (value_start[0] == '\t'))
1774                 value_start++;
1775
1776         value_end = strchr(value_start, '<');
1777         if (!value_end) {
1778                 debug_error(DEBUG, "error: incorrect XML\n");
1779                 return MMFILE_UTIL_FAIL;
1780         }
1781
1782         value_length = value_end - value_start;
1783         while ((value_length >= 1) && ((value_start[value_length - 1] == ' ') || (value_start[value_length - 1] == '\t')))
1784                 value_length--;
1785
1786         int i = 0;
1787         if (value_start[i] == '+' || value_start[i] == '-')
1788                         i++;
1789         while (i < value_length) {
1790                 if (value_start[i] < '0' || value_start[i] > '9') {
1791                         debug_error(DEBUG, "error: incorrect value, integer was expected\n");
1792                         return MMFILE_UTIL_FAIL;
1793                 }
1794                 i++;
1795         }
1796
1797         if (value_length >= value_length_max || value_length < 1) {
1798                 debug_error(DEBUG, "error: empty XML value or incorrect range\n");
1799                 return MMFILE_UTIL_FAIL;
1800         }
1801
1802         memset(init_view_ret, 0x00, sizeof(init_view_ret));
1803         SAFE_STRLCPY(init_view_ret, value_start, sizeof(init_view_ret));
1804
1805         *value = strtol(init_view_ret, &endptr, 10);
1806         if (endptr == init_view_ret) {
1807                 debug_error(DEBUG, "error: no digits were found\n");
1808                 return MMFILE_UTIL_FAIL;
1809         }
1810
1811         return MMFILE_UTIL_SUCCESS;
1812 }
1813
1814 int mm_file_get_string_value_from_xml_string(const char* xml_str, const char* param_name, char** value)
1815 {
1816         char *value_start, *value_end;
1817         const short value_length_max = 256;
1818         int value_length = 0;
1819
1820         if (!xml_str || !param_name || !strstr(xml_str, param_name)) {
1821                 debug_error(DEBUG, "error: incorrect or non-existing parameter\n");
1822                 return MMFILE_UTIL_FAIL;
1823         }
1824
1825         value_start = strstr(xml_str, param_name) + strlen(param_name);
1826         while ((value_start[0] == ' ') || (value_start[0] == '\t'))
1827                 value_start++;
1828
1829         value_end = strchr(value_start, '<');
1830         if (!value_end) {
1831                 debug_error(DEBUG, "error: incorrect XML\n");
1832                 return MMFILE_UTIL_FAIL;
1833         }
1834
1835         value_length = value_end - value_start;
1836         while ((value_length >= 1) && ((value_start[value_length - 1] == ' ') || (value_start[value_length - 1] == '\t')))
1837                 value_length--;
1838
1839         if (value_length >= value_length_max || value_length < 1) {
1840                 debug_error(DEBUG, "error: empty XML value or incorrect range\n");
1841                 return MMFILE_UTIL_FAIL;
1842         }
1843
1844         *value = (char*)calloc(value_length, sizeof(char));
1845         if (*value == NULL) {
1846                 debug_error(DEBUG, "error: calloc failed\n");
1847                 return MMFILE_UTIL_FAIL;
1848         }
1849         strncpy(*value, value_start, value_length);
1850
1851         return MMFILE_UTIL_SUCCESS;
1852 }
1853
1854 int mm_file_get_bool_value_from_xml_string(const char* xml_str, const char* param_name, bool* value)
1855 {
1856         char *value_start = NULL;
1857         char *value_end = NULL;
1858         int value_length = 0;
1859
1860         if (!xml_str || !param_name || !strstr(xml_str, param_name)) {
1861                 debug_error(DEBUG, "error: incorrect or non-existing parameter\n");
1862                 return MMFILE_UTIL_FAIL;
1863         }
1864
1865         value_start = strstr(xml_str, param_name) + strlen(param_name);
1866         while ((value_start != NULL) && ((value_start[0] == ' ') || (value_start[0] == '\t')))
1867                 value_start++;
1868
1869         value_end = strchr(value_start, '<');
1870         if (value_end == NULL) {
1871                 debug_error(DEBUG, "error: incorrect XML.");
1872                 return MMFILE_UTIL_FAIL;
1873         }
1874
1875         value_length = value_end - value_start;
1876         while ((value_length >= 1) && ((value_start[value_length - 1] == ' ') || (value_start[value_length - 1] == '\t')))
1877                 value_length--;
1878
1879         if (value_length < 1) {
1880                 debug_error(DEBUG, "error: empty XML value or incorrect range\n");
1881                 return MMFILE_UTIL_FAIL;
1882         }
1883
1884         *value = strstr(value_start, "true") ? true : false;
1885
1886         return MMFILE_UTIL_SUCCESS;
1887 }
1888
1889 static int g_junk_counter_limit = 0;
1890 static int GetJunkCounterLimit(void)
1891 {
1892         dictionary *dict = NULL;
1893         int data = 0;
1894
1895         dict = iniparser_load(MM_FILE_INI_PATH);
1896         if (!dict) {
1897                 debug_error(DEBUG, "%s load failed", MM_FILE_INI_PATH);
1898                 return -1;
1899         }
1900
1901         data = iniparser_getint(dict, "mm-file-config:junk_counter_limit", 0);
1902         debug_msg(DEBUG, "mm-file-config:junk_counter_limit= %u", data);
1903
1904         iniparser_freedict(dict);
1905
1906         return data;
1907 }
1908
1909 int ParseSpatialVideoMetadataFromXMLString(const char *xmlStr, MMFileFormatContext *formatContext)
1910 {
1911         const char is_spherical_str[] = "<GSpherical:Spherical>";
1912         const char is_stitched_str[] = "<GSpherical:Stitched>";
1913         const char stitching_software_str[] = "<GSpherical:StitchingSoftware>";
1914         const char projection_type_str[] = "<GSpherical:ProjectionType>";
1915         const char stereo_mode_str[] = "<GSpherical:StereoMode>";
1916         const char source_count_str[] = "<GSpherical:SourceCount>";
1917         const char init_view_heading_str[] = "<GSpherical:InitialViewHeadingDegrees>";
1918         const char init_view_pitch_str[] = "<GSpherical:InitialViewPitchDegrees>";
1919         const char init_view_roll_str[] = "<GSpherical:InitialViewRollDegrees>";
1920         const char timestamp_str[] = "<GSpherical:Timestamp>";
1921         const char full_pano_width_str[] = "<GSpherical:FullPanoWidthPixels>";
1922         const char full_pano_height_str[] = "<GSpherical:FullPanoHeightPixels>";
1923         const char cropped_area_image_width_str[] = "<GSpherical:CroppedAreaImageWidthPixels>";
1924         const char cropped_area_image_height_str[] = "<GSpherical:CroppedAreaImageHeightPixels>";
1925         const char cropped_area_left_str[] = "<GSpherical:CroppedAreaLeftPixels>";
1926         const char cropped_area_top_str[] = "<GSpherical:CroppedAreaTopPixels>";
1927
1928         mm_file_get_bool_value_from_xml_string(xmlStr, is_spherical_str, (bool*)&formatContext->isSpherical);
1929         mm_file_get_bool_value_from_xml_string(xmlStr, is_stitched_str, (bool*)&formatContext->isStitched);
1930
1931         debug_msg(RELEASE, "isSpherical = %d", formatContext->isSpherical);
1932         debug_msg(RELEASE, "isStitched = %d", formatContext->isStitched);
1933
1934         if (formatContext->isSpherical && formatContext->isStitched) {
1935                 mm_file_get_string_value_from_xml_string(xmlStr, stitching_software_str, &formatContext->stitchingSoftware);
1936                 mm_file_get_string_value_from_xml_string(xmlStr, projection_type_str, &formatContext->projectionType);
1937                 mm_file_get_string_value_from_xml_string(xmlStr, stereo_mode_str, &formatContext->stereoMode);
1938                 mm_file_get_int_value_from_xml_string(xmlStr, source_count_str, &formatContext->sourceCount);
1939                 mm_file_get_int_value_from_xml_string(xmlStr, init_view_heading_str, &formatContext->initViewHeading);
1940                 mm_file_get_int_value_from_xml_string(xmlStr, init_view_pitch_str, &formatContext->initViewPitch);
1941                 mm_file_get_int_value_from_xml_string(xmlStr, init_view_roll_str, &formatContext->initViewRoll);
1942                 mm_file_get_int_value_from_xml_string(xmlStr, timestamp_str, &formatContext->timestamp);
1943                 mm_file_get_int_value_from_xml_string(xmlStr, full_pano_width_str, &formatContext->fullPanoWidth);
1944                 mm_file_get_int_value_from_xml_string(xmlStr, full_pano_height_str, &formatContext->fullPanoHeight);
1945                 mm_file_get_int_value_from_xml_string(xmlStr, cropped_area_image_width_str, &formatContext->croppedAreaImageWidth);
1946                 mm_file_get_int_value_from_xml_string(xmlStr, cropped_area_image_height_str, &formatContext->croppedAreaImageHeight);
1947                 mm_file_get_int_value_from_xml_string(xmlStr, cropped_area_left_str, &formatContext->croppedAreaLeft);
1948                 mm_file_get_int_value_from_xml_string(xmlStr, cropped_area_top_str, &formatContext->croppedAreaTop);
1949
1950                 debug_msg(RELEASE, "stitchingSoftware = %s", formatContext->stitchingSoftware);
1951                 debug_msg(RELEASE, "projectionType = %s", formatContext->projectionType);
1952                 debug_msg(RELEASE, "stereoMode = %s", formatContext->stereoMode);
1953                 debug_msg(RELEASE, "sourceCount %d", formatContext->sourceCount);
1954                 debug_msg(RELEASE, "initViewHeading = %d", formatContext->initViewHeading);
1955                 debug_msg(RELEASE, "initViewPitch = %d", formatContext->initViewPitch);
1956                 debug_msg(RELEASE, "initViewRoll = %d", formatContext->initViewRoll);
1957                 debug_msg(RELEASE, "timestamp = %d", formatContext->timestamp);
1958                 debug_msg(RELEASE, "fullPanoWidthPixels = %d", formatContext->fullPanoWidth);
1959                 debug_msg(RELEASE, "fullPanoHeightPixels = %d", formatContext->fullPanoHeight);
1960                 debug_msg(RELEASE, "croppedAreaImageWidth = %d", formatContext->croppedAreaImageWidth);
1961                 debug_msg(RELEASE, "croppedAreaImageHeight = %d", formatContext->croppedAreaImageHeight);
1962                 debug_msg(RELEASE, "croppedAreaLeft = %d", formatContext->croppedAreaLeft);
1963                 debug_msg(RELEASE, "croppedAreaTop = %d", formatContext->croppedAreaTop);
1964         }
1965
1966         return MMFILE_UTIL_SUCCESS;
1967 }
1968
1969 #define BIG_CONTENT_BOX_SIZE_LEN 8
1970
1971 int MMFileUtilGetMetaDataFromMKV(MMFileFormatContext *formatContext)
1972 {
1973         MMFileIOHandle *fp = NULL;
1974         int probe_size = 10000;
1975         unsigned char *buffer = NULL;
1976         int ret = 0;
1977         int i;
1978         long long file_size = 0;
1979
1980         MMFILE_WEBM_PROJ_V2_BOX v2box = { 0, };
1981         MMFILE_WEBM_EQUI_PROJ_V2_BOX equi = { 0, };
1982         MMFILE_WEBM_CBMP_PROJ_V2_BOX cbmp = { 0, };
1983         MMFILE_WEBM_POSE_ELEMENT_V2_BOX pose = { 0, };
1984
1985         ret = mmfile_open(&fp, formatContext->uriFileName, MMFILE_RDONLY);
1986         if (ret == MMFILE_UTIL_FAIL) {
1987                 debug_error(DEBUG, "error: mmfile_open\n");
1988                 goto exit;
1989         }
1990
1991         file_size = mmfile_seek(fp, 0, SEEK_END);
1992         if (file_size == MMFILE_UTIL_FAIL) {
1993                 debug_error(DEBUG, "mmfile operation failed\n");
1994                 goto exit;
1995         }
1996
1997         probe_size = (file_size > probe_size) ? probe_size : file_size;
1998         buffer = (unsigned char *)malloc(probe_size * sizeof(unsigned char));
1999         if (!buffer) {
2000                 debug_error(DEBUG, "malloc failed\n");
2001                 goto exit;
2002         }
2003
2004         ret = mmfile_seek(fp, 0, SEEK_SET);
2005         if (ret == MMFILE_UTIL_FAIL) {
2006                 debug_error(DEBUG, "mmfile operation failed\n");
2007                 goto exit;
2008         }
2009
2010         ret = mmfile_read(fp, buffer, probe_size * sizeof(unsigned char));
2011         if (ret == MMFILE_UTIL_FAIL) {
2012                 debug_error(DEBUG, "mmfile operation failed\n");
2013                 goto exit;
2014         }
2015
2016         /* FIXME (m.alieksieie): It's better to use some EBML parser here*/
2017         for (i = 0; i + 3 < probe_size; ++i) {
2018                 if (*(unsigned int *)(buffer + i) == FOURCC('e', 'q', 'u', 'i') ||
2019                                 *(unsigned int *)(buffer + i) == FOURCC('c', 'b', 'm', 'p')) {
2020                         debug_msg(DEBUG, "projection data found at offset %d bytes\n", i);
2021                         break;
2022                 }
2023         }
2024
2025         if (i + 3 == probe_size) {
2026                 debug_msg(DEBUG, "projection info wasn't found\n");
2027                 ret = MMFILE_UTIL_SUCCESS;
2028                 goto exit;
2029         }
2030
2031         if ((i - (int)sizeof(MMFILE_WEBM_PROJ_V2_BOX)) < 0) {
2032                 debug_error(DEBUG, "error: invalid supposed projection info location\n");
2033                 ret = MMFILE_UTIL_FAIL;
2034                 goto exit;
2035         }
2036
2037         ret = mmfile_seek(fp, i - sizeof(MMFILE_WEBM_PROJ_V2_BOX), SEEK_SET);
2038         if (ret == MMFILE_UTIL_FAIL) {
2039                 debug_error(DEBUG, "error: failed to seek to the supposed projection info location\n");
2040                 goto exit;
2041         }
2042
2043         ret = mmfile_read(fp, (unsigned char *)&v2box, sizeof(MMFILE_WEBM_PROJ_V2_BOX));
2044         if (ret == MMFILE_UTIL_FAIL) {
2045                 debug_error(DEBUG, "mmfile operation failed\n");
2046                 goto exit;
2047         }
2048
2049         if (v2box.proj_type_box_value == PROJECTION_TYPE_EQUI) {
2050                 debug_msg(DEBUG, "Equirectangular projection is used\n");
2051
2052                 ret = mmfile_read(fp, (unsigned char *)&equi, sizeof(MMFILE_WEBM_EQUI_PROJ_V2_BOX));
2053                 if (ret == MMFILE_UTIL_FAIL) {
2054                         debug_error(DEBUG, "error: failed to read equirectangular element\n");
2055                         goto exit;
2056                 }
2057                 if (strncmp((char *)equi.proj_priv_box_name, "equi", 4) == 0) {
2058                         formatContext->equiBoundsTopV2 = mmfile_io_be_uint32(equi.equi_projection_bounds_top);
2059                         formatContext->equiBoundsBottomV2 = mmfile_io_be_uint32(equi.equi_projection_bounds_bottom);
2060                         formatContext->equiBoundsLeftV2 = mmfile_io_be_uint32(equi.equi_projection_bounds_left);
2061                         formatContext->equiBoundsRightV2 = mmfile_io_be_uint32(equi.equi_projection_bounds_right);
2062                 } else {
2063                         debug_error(DEBUG, "error: failed to read equirectangular element\n");
2064                         ret = MMFILE_UTIL_SUCCESS;
2065                         goto exit;
2066                 }
2067         }
2068         if (v2box.proj_type_box_value == PROJECTION_TYPE_CBMP) {
2069                 debug_msg(DEBUG, "Cubemap projection is used\n");
2070
2071                 ret = mmfile_read(fp, (unsigned char *)&cbmp, sizeof(MMFILE_WEBM_CBMP_PROJ_V2_BOX));
2072                 if (ret == MMFILE_UTIL_FAIL) {
2073                         debug_error(DEBUG, "error: failed to read cubemap element\n");
2074                         goto exit;
2075                 }
2076                 if (strncmp((char *)cbmp.proj_priv_box_name, "cbmp", 4) == 0) {
2077                         formatContext->cbmpLayoutV2 = mmfile_io_be_uint32(cbmp.cbmp_projection_layout);
2078                         formatContext->cbmpPaddingV2 = mmfile_io_be_uint32(cbmp.cbmp_projection_padding);
2079                 } else {
2080                         debug_error(DEBUG, "error: failed to read cubemap element\n");
2081                         ret = MMFILE_UTIL_FAIL;
2082                         goto exit;
2083                 }
2084         }
2085
2086         ret = mmfile_read(fp, (unsigned char *)&pose, sizeof(MMFILE_WEBM_POSE_ELEMENT_V2_BOX));
2087         if (ret == MMFILE_UTIL_FAIL) {
2088                 debug_error(DEBUG, "error: failed to read pose info\n");
2089                 goto exit;
2090         }
2091
2092         if (pose.pose_yaw_element_id == POSE_YAW_ELEMENT_ID) {
2093                 formatContext->poseYawV2 = (uint)mmfile_io_be_float32(pose.pose_yaw_element_value);
2094         } else {
2095                 debug_error(DEBUG, "error: failed to pose yaw element\n");
2096                 ret = MMFILE_UTIL_FAIL;
2097                 goto exit;
2098         }
2099         if (pose.pose_pitch_element_id == POSE_PITCH_ELEMENT_ID) {
2100                 formatContext->posePitchV2 = (uint)mmfile_io_be_float32(pose.pose_pitch_element_value);
2101         } else {
2102                 debug_error(DEBUG, "error: failed to pose pitch element\n");
2103                 ret = MMFILE_UTIL_FAIL;
2104                 goto exit;
2105         }
2106         if (pose.pose_roll_element_id == POSE_ROLL_ELEMENT_ID) {
2107                 formatContext->poseRollV2 = (uint)mmfile_io_be_float32(pose.pose_roll_element_value);
2108         } else {
2109                 debug_error(DEBUG, "error: failed to pose roll element\n");
2110                 ret = MMFILE_UTIL_FAIL;
2111                 goto exit;
2112         }
2113
2114 exit:
2115         mmfile_close(fp);
2116
2117         if (buffer)
2118                 free(buffer);
2119
2120         return ret;
2121 }
2122
2123 EXPORT_API int MMFileUtilGetMetaDataFromMP4(MMFileFormatContext *formatContext)
2124 {
2125         MMFileIOHandle *fp = NULL;
2126         int ret = 0;
2127         int readed;
2128         unsigned long long chunk_size = 0;
2129         long long moov_end = 0;
2130         MMFILE_MP4_BASIC_BOX_HEADER basic_header = {0, };
2131         int junk_counter = 0;
2132
2133         ret = mmfile_open(&fp, formatContext->uriFileName, MMFILE_RDONLY);
2134         if (ret == MMFILE_UTIL_FAIL) {
2135                 debug_error(DEBUG, "error: mmfile_open\n");
2136                 goto exit;
2137         }
2138
2139         basic_header.start_offset = mmfile_tell(fp);
2140
2141         if (g_junk_counter_limit == 0)
2142                 g_junk_counter_limit = GetJunkCounterLimit();
2143
2144         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)) {
2145                 basic_header.size = mmfile_io_be_uint32(basic_header.size);
2146                 basic_header.type = mmfile_io_le_uint32(basic_header.type);
2147
2148                 if (basic_header.size == 0) {
2149                         debug_warning(DEBUG, "header is invalid.\n");
2150                         basic_header.size = readed;
2151                         basic_header.type = 0;
2152                         chunk_size = basic_header.size;
2153
2154                         if ((moov_end != 0) && (moov_end < basic_header.start_offset)) {
2155                                 debug_msg(DEBUG, "found junk data but moov data already was extracted, so junk counter will be increase: %d", junk_counter);
2156                                 junk_counter++;
2157
2158                                 /* stop the loop for junk case. */
2159                                 if ((g_junk_counter_limit > 0) && (junk_counter > g_junk_counter_limit)) {
2160                                         debug_msg(DEBUG, "stop the loop by junk-data checker");
2161                                         ret = MMFILE_UTIL_FAIL;
2162                                         continue;
2163                                 }
2164                         }
2165                 } else if (basic_header.size == 1) {
2166                         int i = 0;
2167                         unsigned char temp[BIG_CONTENT_BOX_SIZE_LEN] = {0, };
2168                         unsigned long long size = 0;
2169
2170                         mmfile_read(fp, (unsigned char *)&temp, BIG_CONTENT_BOX_SIZE_LEN);
2171
2172                         for (i = 0; i < BIG_CONTENT_BOX_SIZE_LEN; i++)
2173                                 size |= (unsigned long long)temp[i] << (BIG_CONTENT_BOX_SIZE_LEN - 1 - i) * BIG_CONTENT_BOX_SIZE_LEN;
2174                         chunk_size = size;
2175                         junk_counter = 0;
2176                 } else {
2177                         chunk_size = basic_header.size;
2178                         junk_counter = 0;
2179                 }
2180
2181                 switch (basic_header.type) {
2182                         case FOURCC('m', 'o', 'o', 'v'): {
2183                                         debug_msg(RELEASE, "MPEG4: [moov] SIZE: [%lld]Byte\n", chunk_size);
2184                                         moov_end = basic_header.start_offset + chunk_size;
2185                                         break;
2186                                 }
2187                         case FOURCC('u', 'd', 't', 'a'): {
2188                                         debug_msg(RELEASE, "MPEG4: [udat] SIZE: [%lld]Byte\n", chunk_size);
2189                                         break;
2190                                 }
2191                                 /*/////////////////////////////////////////////////////////////// */
2192                                 /*                  Extracting Tag Data                        // */
2193                                 /*/////////////////////////////////////////////////////////////// */
2194                         case FOURCC('t', 'i', 't', 'l'): {
2195                                         debug_msg(RELEASE, "MPEG4: [titl] SIZE: [%lld]Byte\n", chunk_size);
2196                                         GetStringFromTextTagBox(formatContext, fp, &basic_header, eMMFILE_3GP_TAG_TITLE);
2197                                         break;
2198                                 }
2199                         case FOURCC('d', 's', 'c', 'p'): {
2200                                         debug_msg(RELEASE, "MPEG4: [dscp] SIZE: [%lld]Byte\n", chunk_size);
2201                                         GetStringFromTextTagBox(formatContext, fp, &basic_header, eMMFILE_3GP_TAG_CAPTION);
2202                                         break;
2203                                 }
2204                         case FOURCC('c', 'p', 'r', 't'): {
2205                                         debug_msg(RELEASE, "MPEG4: [cprt] SIZE: [%lld]Byte\n", chunk_size);
2206                                         GetStringFromTextTagBox(formatContext, fp, &basic_header, eMMFILE_3GP_TAG_COPYRIGHT);
2207                                         break;
2208                                 }
2209                         case FOURCC('p', 'e', 'r', 'f'): {
2210                                         debug_msg(RELEASE, "MPEG4: [perf] SIZE: [%lld]Byte\n", chunk_size);
2211                                         GetStringFromTextTagBox(formatContext, fp, &basic_header, eMMFILE_3GP_TAG_PERFORMER);
2212                                         break;
2213                                 }
2214                         case FOURCC('a', 'u', 't', 'h'): {
2215                                         debug_msg(RELEASE, "MPEG4: [auth] SIZE: [%lld]Byte\n", chunk_size);
2216                                         GetStringFromTextTagBox(formatContext, fp, &basic_header, eMMFILE_3GP_TAG_AUTHOR);
2217                                         break;
2218                                 }
2219                         case FOURCC('g', 'n', 'r', 'e'): {
2220                                         debug_msg(RELEASE, "MPEG4: [gnre] SIZE: [%lld]Byte\n", chunk_size);
2221                                         GetStringFromTextTagBox(formatContext, fp, &basic_header, eMMFILE_3GP_TAG_GENRE);
2222                                         break;
2223                                 }
2224                         case FOURCC('a', 'l', 'b', 'm'): {
2225                                         debug_msg(RELEASE, "MPEG4: [albm] SIZE: [%lld]Byte\n", chunk_size);
2226                                         GetAlbumFromAlbumTagBox(formatContext, fp, &basic_header);
2227                                         break;
2228                                 }
2229                         case FOURCC('y', 'r', 'r', 'c'): {
2230                                         debug_msg(RELEASE, "MPEG4: [yrrc] SIZE: [%lld]Byte\n", chunk_size);
2231                                         GetYearFromYearTagBox(formatContext, fp, &basic_header);
2232                                         break;
2233                                 }
2234                         case FOURCC('r', 't', 'n', 'g'): {
2235                                         debug_msg(RELEASE, "MPEG4: [rtng] SIZE: [%lld]Byte\n", chunk_size);
2236                                         GetRatingFromRatingTagBox(formatContext, fp, &basic_header);  /* not use */
2237                                         break;
2238                                 }
2239                         case FOURCC('c', 'l', 's', 'f'): {
2240                                         debug_msg(RELEASE, "MPEG4: [clsf] SIZE: [%lld]Byte\n", chunk_size);
2241                                         GetClassficationFromClsfTagBox(formatContext, fp, &basic_header);
2242                                         break;
2243                                 }
2244                         case FOURCC('k', 'y', 'w', 'd'): {
2245                                         debug_msg(RELEASE, "MPEG4: [kywd] SIZE: [%lld]Byte\n", chunk_size);
2246                                         ret = mmfile_seek(fp, basic_header.start_offset + chunk_size, SEEK_SET);
2247                                         break;
2248                                 }
2249                         case FOURCC('l', 'o', 'c', 'i'): {
2250                                         debug_msg(RELEASE, "MPEG4: [loci] SIZE: [%lld]Byte\n", chunk_size);
2251                                         GetLocationFromLociTagBox(formatContext, fp, &basic_header);
2252                                         break;
2253                                 }
2254                                 /* Check smta in user data field (moov) to be compatible with android */
2255                         case FOURCC('s', 'm', 't', 'a'): {
2256                                         debug_msg(RELEASE, "MPEG4: [smta] SIZE: [%lld]Byte\n", chunk_size);
2257                                         GetSAUTInfoFromSMTATagBox(formatContext, fp, &basic_header);
2258                                         break;
2259                                 }
2260                                 /* Check cdis in user data field (moov) to be compatible with android */
2261                         case FOURCC('c', 'd', 'i', 's'): {
2262                                         debug_msg(RELEASE, "MPEG4: [smta] SIZE: [%lld]Byte\n", chunk_size);
2263                                         GetValueFromCDISTagBox(formatContext, fp, &basic_header);
2264                                         break;
2265                                 }
2266                                 /*/////////////////////////////////////////////////////////////// */
2267                                 /*                  Extracting ID3 Tag Data                    // */
2268                                 /*/////////////////////////////////////////////////////////////// */
2269                         case FOURCC('m', 'e', 't', 'a'): {
2270                                         debug_msg(RELEASE, "MPEG4: [meta] SIZE: [%lld]Byte\n", chunk_size);
2271                                         GetTagFromMetaBox(formatContext, fp, &basic_header);
2272                                         break;
2273                                 }
2274
2275                         case FOURCC('t', 'r', 'a', 'k'): {
2276                                         debug_msg(RELEASE, "MPEG4: [trak] SIZE: [%lld]Byte\n", chunk_size);
2277                                         break;
2278                                 }
2279                         case FOURCC('u', 'u', 'i', 'd'): {
2280                                         unsigned long uuid[4] = {0, };
2281
2282                                         debug_msg(RELEASE, "MPEG4: [uuid] SIZE: [%lld]Byte\n", chunk_size);
2283
2284                                         mmfile_read(fp, (unsigned char *)uuid, sizeof(uuid));
2285
2286                                         if (mmfile_io_be_uint32(uuid[0]) == 0xffcc8263
2287                                                 && mmfile_io_be_uint32(uuid[1]) == 0xf8554a93
2288                                                 && mmfile_io_be_uint32(uuid[2]) == 0x8814587a
2289                                                 && mmfile_io_be_uint32(uuid[3]) == 0x02521fdd) {
2290                                                 char *str = NULL;
2291                                                 str = (char *)malloc(basic_header.size);
2292
2293                                                 if (str != NULL) {
2294                                                         memset(str, 0, basic_header.size);
2295                                                         mmfile_read(fp, (unsigned char *)str, basic_header.size);
2296 #if 0
2297 /* The block is superseded */
2298                                                         if (strstr(str, "<GSpherical:Spherical>true</GSpherical:Spherical>"))
2299                                                                 formatContext->is_360 = 1;
2300                                                         else
2301                                                                 formatContext->is_360 = 0;
2302 /* Image can be stitched even if it is not spherical */
2303                                                         if (formatContext->is_360 == 1) {
2304                                                                 if (strstr(str, "<GSpherical:Stitched>true</GSpherical:Stitched>"))
2305                                                                         formatContext->stitched = MMFILE_360_STITCHED;
2306                                                                 else
2307                                                                         formatContext->stitched = MMFILE_360_NON_STITCHED;
2308                                                         } else {
2309 /* Image can be stitched or non-stitched. Usage of some 3rd value is superfluous */
2310                                                                 formatContext->stitched = MMFILE_360_NONE;
2311                                                         }
2312 #endif
2313
2314                                                         debug_msg(RELEASE, "Extracting tags from UUID XML string %s\n", str);
2315
2316                                                         ParseSpatialVideoMetadataFromXMLString(str, formatContext);
2317                                                 }
2318                                         }
2319                                         ret = mmfile_seek(fp, basic_header.start_offset + chunk_size, SEEK_SET);
2320
2321                                         break;
2322                                 }
2323                         case FOURCC('m', 'd', 'i', 'a'): {
2324                                         debug_msg(RELEASE, "MPEG4: [mdia] SIZE: [%lld]Byte\n", chunk_size);
2325                                         break;
2326                                 }
2327                         case FOURCC('m', 'i', 'n', 'f'): {
2328                                         debug_msg(RELEASE, "MPEG4: [minf] SIZE: [%lld]Byte\n", chunk_size);
2329                                         break;
2330                                 }
2331                         case FOURCC('s', 't', 'b', 'l'): {
2332                                         debug_msg(RELEASE, "MPEG4: [stbl] SIZE: [%lld]Byte\n", chunk_size);
2333                                         break;
2334                                 }
2335                         case FOURCC('s', 't', 's', 'd'): {
2336                                         debug_msg(RELEASE, "MPEG4: [stsd] SIZE: [%lld]Byte\n", chunk_size);
2337                                         break;
2338                                 }
2339                         case FOURCC('m', 'p', '4', 'a'): {
2340                                         debug_msg(RELEASE, "MPEG4: [mp4a] SIZE: [%lld]Byte\n", chunk_size);
2341                                         GetSA3DInfoFromMP4ATagBox(formatContext, fp, &basic_header);
2342                                         ret = mmfile_seek(fp, basic_header.start_offset + chunk_size, SEEK_SET);
2343                                         break;
2344                                 }
2345                         case FOURCC('a', 'v', 'c', '1'): {
2346                                         debug_msg(RELEASE, "MPEG4: [avc1] SIZE: [%lld]Byte (offset: %lld)\n", chunk_size, basic_header.start_offset);
2347                                         GetVideoV2MetadataFromAvc1TagBox(formatContext, fp, &basic_header);
2348                                         break;
2349                                 }
2350                         default: {
2351                                         debug_msg(RELEASE, "4CC: Not Support [%c%c%c%c]. So skip it. Size [%lld Byte]\n",
2352                                                                 ((char *)&basic_header.type)[0], ((char *)&basic_header.type)[1],
2353                                                                 ((char *)&basic_header.type)[2], ((char *)&basic_header.type)[3], chunk_size);
2354                                         ret = mmfile_seek(fp, basic_header.start_offset + chunk_size, SEEK_SET);
2355                                         break;
2356                                 }
2357                 }
2358
2359                 if (ret == MMFILE_UTIL_FAIL) {
2360                         debug_error(DEBUG, "mmfile operation is error\n");
2361                         ret = -1;
2362                         goto exit;
2363                 }
2364
2365                 long long new_pos = mmfile_tell(fp);
2366
2367                 if ((moov_end == 0) && (new_pos <= basic_header.start_offset)) {
2368                         debug_error(DEBUG, "Wrong position");
2369                         ret = MMFILE_UTIL_FAIL;
2370                         continue;
2371                 }
2372                 basic_header.start_offset = new_pos;
2373
2374         }
2375
2376 exit:
2377         mmfile_close(fp);
2378         return ret;
2379 }
2380
2381 static char *get_string(const char *buf, int buf_size, int *bytes_written)
2382 {
2383         int i = 0, c = 0;
2384         char *q = NULL;
2385         char str[512] = {0, };
2386
2387         q = str;
2388         for (i = 0; i < buf_size; i++) {
2389                 c = buf[i];
2390                 if (c == '\0')
2391                         break;
2392                 if ((q - str) >= (int)sizeof(str) - 1)
2393                         break;
2394                 *q++ = c;
2395         }
2396         *q = '\0';
2397
2398         if (strlen(str) > 0) {
2399                 *bytes_written = strlen(str);
2400                 return strdup(str);
2401         } else {
2402                 *bytes_written = 0;
2403                 return NULL;
2404         }
2405 }
2406
2407 char *rtrimN(char *pStr)
2408 {
2409         int pos = 0;
2410         pos = strlen(pStr) - 1;
2411         for (; pos >= 0; pos--) {
2412                 if (pStr[pos] == 0x20) {
2413                         pStr[pos] = 0x00;
2414                 } else {
2415                         break;
2416                 }
2417         }
2418
2419         return strdup(pStr);
2420 }
2421
2422 bool safe_atoi(char *buffer, int *si)
2423
2424 {
2425         char *end;
2426         errno = 0;
2427
2428         const long sl = strtol(buffer, &end, 10);
2429
2430         if (end == buffer) {
2431                 debug_error(RELEASE, "not a decimal number");
2432                 return FALSE;
2433         } else if ('\0' != *end) {
2434                 debug_error(RELEASE, "extra characters at end of input: %s", end);
2435                 return FALSE;
2436         } else if ((LONG_MIN == sl || LONG_MAX == sl) && (ERANGE == errno)) {
2437                 debug_error(RELEASE, "out of range of type long");
2438                 return FALSE;
2439         } else if (sl > INT_MAX) {
2440                 debug_error(RELEASE, "greater than INT_MAX");
2441                 return FALSE;
2442         } else if (sl < INT_MIN) {
2443                 debug_error(RELEASE, "less than INT_MIN");
2444                 return FALSE;
2445         } else {
2446                 *si = (int)sl;
2447         }
2448         return TRUE;
2449 }
2450
2451 static bool make_characterset_array(char ***charset_array)
2452 {
2453         char *locale = MMFileUtilGetLocale();
2454
2455         *charset_array = calloc(AV_ID3V2_MAX, sizeof(char *));
2456
2457         if (*charset_array == NULL) {
2458                 debug_error(DEBUG, "calloc failed ");
2459                 if (locale != NULL)
2460                         free(locale);
2461                 return false;
2462         }
2463
2464         if (locale != NULL) {
2465                 (*charset_array)[AV_ID3V2_ISO_8859] = strdup(locale);
2466         } else {
2467                 debug_error(DEBUG, "get locale failed");
2468                 (*charset_array)[AV_ID3V2_ISO_8859] = NULL;
2469         }
2470
2471         (*charset_array)[AV_ID3V2_UTF16] = strdup("UCS2");
2472         (*charset_array)[AV_ID3V2_UTF16_BE] = strdup("UTF16-BE");
2473         (*charset_array)[AV_ID3V2_UTF8] = strdup("UTF-8");
2474
2475         return true;
2476 }
2477
2478 static bool release_characterset_array(char **charset_array)
2479 {
2480         int i = 0;
2481
2482         for (i = 0; i < AV_ID3V2_MAX; i++) {
2483                 if (charset_array[i] != NULL) {
2484                         free(charset_array[i]);
2485                         charset_array[i] = NULL;
2486                 }
2487         }
2488
2489         if (charset_array != NULL) {
2490                 free(charset_array);
2491                 charset_array = NULL;
2492         }
2493
2494         return true;
2495 }
2496
2497 static void init_content_info(AvFileContentInfo *pInfo)
2498 {
2499         pInfo->tagV2Info.bTitleMarked = false;
2500         pInfo->tagV2Info.bArtistMarked = false;
2501         pInfo->tagV2Info.bAlbumMarked = false;
2502         pInfo->tagV2Info.bAlbum_ArtistMarked = false;
2503         pInfo->tagV2Info.bYearMarked = false;
2504         pInfo->tagV2Info.bDescriptionMarked = false;
2505         pInfo->tagV2Info.bGenreMarked = false;
2506         pInfo->tagV2Info.bTrackNumMarked = false;
2507         pInfo->tagV2Info.bEncByMarked = false;
2508         pInfo->tagV2Info.bURLMarked = false;
2509         pInfo->tagV2Info.bCopyRightMarked = false;
2510         pInfo->tagV2Info.bOriginArtistMarked = false;
2511         pInfo->tagV2Info.bComposerMarked = false;
2512         pInfo->tagV2Info.bImageMarked = false;
2513
2514         pInfo->tagV2Info.bRecDateMarked = false;
2515         pInfo->tagV2Info.bContentGroupMarked = false;
2516
2517         pInfo->tagV2Info.bUnsyncLyricsMarked = false;
2518         pInfo->tagV2Info.bSyncLyricsMarked = false;
2519         pInfo->tagV2Info.bConductorMarked = false;
2520         pInfo->tagV2Info.bGenreUTF16 = false;
2521
2522         pInfo->imageInfo.bURLInfo = false;
2523         pInfo->imageInfo.pImageBuf = NULL;
2524         pInfo->imageInfo.imageLen = 0;
2525 }
2526
2527 static void _mm_file_id3tag_add_bracket_at_genre(char **genre, int genre_len)
2528 {
2529         int int_genre = -1;
2530         char tmp_genre[6] = {0, };
2531         int tmp_genre_len = 0;
2532
2533         if (!genre || !(*genre) || genre_len <= 0)
2534                 return;
2535
2536         if (!safe_atoi(*genre, &int_genre)) {
2537                 debug_log(RELEASE, "genre information is not integer [%s]", *genre);
2538                 return;
2539         }
2540
2541         debug_msg(RELEASE, "genre information is integer [%d]", int_genre);
2542
2543         /* if the value is not kinds of genre, exit */
2544         if (int_genre < 0 || int_genre >= GENRE_COUNT)
2545                 return;
2546
2547         /* Change int to string with bracket like "(123)"
2548          * mm_file_id3tag_restore_content_info convert it to string
2549          */
2550         memset(tmp_genre, 0, sizeof(tmp_genre));
2551         snprintf(tmp_genre, sizeof(tmp_genre), "(%d)", int_genre);
2552
2553         tmp_genre_len = strlen(tmp_genre);
2554         if (tmp_genre_len > 0) {
2555                 *genre = mmfile_realloc(*genre, sizeof(char) * (tmp_genre_len + 1));
2556                 if (*genre)
2557                         SAFE_STRLCPY(*genre, tmp_genre, tmp_genre_len + 1);
2558         }
2559 }
2560
2561 static bool __id3tag_parse_PIC_format(AvFileContentInfo *pInfo, unsigned char *pTagVal, int *offset)
2562 {
2563         unsigned int idx = 0;
2564
2565         /* get the mime type of Attached PICture, it is text string */
2566
2567         if (pTagVal[*offset] == '\0') {
2568                 debug_msg(RELEASE, "The picture format of PIC is not included\n");
2569                 return false;
2570         }
2571
2572         /* init ext variable */
2573         memset(pInfo->imageInfo.imageExt, 0, sizeof(pInfo->imageInfo.imageExt));
2574         /* get ext */
2575         while ((idx < MP3_ID3_IMAGE_EXT_MAX_LENGTH - 1) && (pTagVal[idx] != '\0')) {
2576                 pInfo->imageInfo.imageExt[idx] = pTagVal[idx];
2577                 idx++;
2578         }
2579
2580         *offset += idx;
2581
2582         return true;
2583 }
2584
2585 static bool __id3tag_parse_APIC_mimetype(AvFileContentInfo *pInfo, unsigned char *pTagVal, int nTagLen, int *offset)
2586 {
2587         unsigned int idx = 0;
2588         const char *MIME_PRFIX = "image/";
2589
2590         /* get the mime type of Attached PICture, it is text string */
2591
2592         if (pTagVal[*offset] == '\0') {
2593                 pInfo->imageInfo.imgMimetypeLen = 0;
2594                 debug_msg(RELEASE, "The MIME type of APIC is not included\n");
2595                 return false;
2596         }
2597
2598         /* init mimetype variable */
2599         memset(pInfo->imageInfo.imageMIMEType, 0, sizeof(pInfo->imageInfo.imageMIMEType));
2600         /* get mimetype */
2601         while ((idx < MP3_ID3_IMAGE_MIME_TYPE_MAX_LENGTH - 1) && (pTagVal[idx] != '\0')) {
2602                 pInfo->imageInfo.imageMIMEType[idx] = pTagVal[idx];
2603                 idx++;
2604         }
2605         pInfo->imageInfo.imgMimetypeLen = idx;
2606
2607         *offset += idx;
2608
2609         if (strncmp(pInfo->imageInfo.imageMIMEType, MIME_PRFIX, strlen(MIME_PRFIX)) != 0) {
2610                 pInfo->imageInfo.imgMimetypeLen = 0;
2611                 debug_error(DEBUG, "MIME type(%s) is not image", pInfo->imageInfo.imageMIMEType);
2612                 return false;
2613         }
2614
2615         if ((pTagVal[*offset] != '\0') || (nTagLen <= *offset)) {
2616                 debug_msg(RELEASE, "pTagVal[offset](%d) mimetype is not NULL terminated! realCpyFrameNum - offset(%d)\n",
2617                                         pTagVal[*offset], nTagLen - *offset);
2618                 return true;
2619         }
2620
2621         (*offset)++;/* end of MIME('\0', 1byte) */
2622         debug_msg(RELEASE, "after scaning Mime type offset(%d) value!\n", *offset);
2623
2624         return true;
2625 }
2626
2627 static void __id3tag_parse_APIC_pictype(AvFileContentInfo *pInfo, unsigned char *pTagVal, int *offset)
2628 {
2629         /* get the picture type of Attached PICture, it is 1byte(0xff) */
2630
2631         if (pTagVal[*offset] < AV_ID3V2_PICTURE_TYPE_MAX)
2632                 pInfo->imageInfo.pictureType = pTagVal[*offset];
2633         else
2634                 debug_msg(RELEASE, "APIC image has invalid picture type(0x%x)\n", pTagVal[*offset]);
2635
2636         (*offset)++;/* PictureType(1byte) */
2637         debug_msg(RELEASE, "after scaning PictureType(%d) offset(%d) value!\n", pInfo->imageInfo.pictureType, *offset);
2638 }
2639
2640 static void __id3tag_parse_APIC_desc(AvFileContentInfo *pInfo, unsigned char *pTagVal, int nTagLen, const char *pCharSet, int *offset)
2641 {
2642         /* get the description of Attached PICture, it is text string */
2643
2644         int idx = 0;
2645         unsigned int tag_len = 0;
2646         unsigned int desc_len = 0;
2647         char *tmp_desc = NULL;
2648
2649         if (pTagVal[*offset] == 0x0) {
2650                 pInfo->imageInfo.imgDesLen = 0;
2651                 debug_msg(RELEASE, "The description of APIC is not included!!!\n");
2652                 return;
2653         }
2654
2655         while (1) {
2656                 if (pTagVal[*offset + idx] == '\0') {
2657                         if (nTagLen < (*offset + idx)) {
2658                                 debug_error(DEBUG, "End of APIC Tag %d %d %d\n", nTagLen, *offset, idx);
2659                                 break;
2660                         }
2661                         /* check end of image description */
2662                         if ((pTagVal[*offset + idx + 1] == gTagJPEGHeader[0]) ||
2663                                 (pTagVal[*offset + idx + 1] == gTagPNGHeader[0])) {
2664                                 debug_msg(RELEASE, "length of description (%d)", idx);
2665                                 break;
2666                         }
2667                 }
2668                 idx++;
2669         }
2670
2671         tag_len = idx + 1;      /* length of description + '\0' */
2672
2673         tmp_desc = mmfile_calloc(1, sizeof(char) * tag_len);
2674         if (tmp_desc) {
2675                 memcpy(tmp_desc, pTagVal + *offset, tag_len);
2676
2677                 /* convert description */
2678                 pInfo->imageInfo.imageDescription = mmfile_string_convert(tmp_desc, tag_len, "UTF-8", pCharSet, NULL, &desc_len);
2679                 pInfo->imageInfo.imgDesLen = (int)desc_len;
2680                 mmfile_free(tmp_desc);
2681                 debug_msg(RELEASE, "new_desc %s(%d)\n", pInfo->imageInfo.imageDescription, pInfo->imageInfo.imgDesLen);
2682         }
2683
2684         *offset += idx;
2685         if ((pTagVal[*offset] != '\0') || (nTagLen <= *offset)) {
2686                 debug_msg(RELEASE, "pTagVal[offset](%d) description is not NULL terminated! realCpyFrameNum - offset(%d)\n",
2687                                         pTagVal[*offset], nTagLen - *offset);
2688                 return;
2689         }
2690         (*offset)++; /* end of desceription(1byte) */
2691 }
2692
2693 static void __id3tag_parse_APIC_picture(AvFileContentInfo *pInfo, unsigned char *pTagVal, int nTagLen, int *offset)
2694 {
2695         /* get the picture of Attached PICture, it is binary data */
2696
2697         /* some content has useless '\0' in front of picture data */
2698         while (pTagVal[*offset] == '\0') {
2699                 (*offset)++;
2700         }
2701
2702         debug_msg(RELEASE, "after scaning APIC description offset(%d) value!\n", *offset);
2703
2704         if (nTagLen <= *offset) {
2705                 debug_msg(RELEASE, "No APIC image!! realCpyFrameNum(%d) - offset(%d)\n", nTagLen, *offset);
2706                 return;
2707         }
2708
2709         pInfo->imageInfo.imageLen = nTagLen - *offset;
2710         pInfo->imageInfo.pImageBuf = mmfile_malloc(pInfo->imageInfo.imageLen + 1);
2711
2712         if (pInfo->imageInfo.pImageBuf) {
2713                 memcpy(pInfo->imageInfo.pImageBuf, pTagVal + *offset, pInfo->imageInfo.imageLen);
2714                 pInfo->imageInfo.pImageBuf[pInfo->imageInfo.imageLen] = 0;
2715         }
2716
2717         /* if mimetype is "-->", image date has an URL */
2718         if (IS_INCLUDE_URL(pInfo->imageInfo.imageMIMEType))
2719                 pInfo->imageInfo.bURLInfo = true;
2720 }
2721
2722 static void _mm_file_id3tag_parse_PIC(AvFileContentInfo *pInfo, unsigned char *pTagVal, int nTagLen, const char *pCharSet)
2723 {
2724         /* current position to read pTagVal */
2725         int offset = 0;
2726
2727         debug_fenter(RELEASE);
2728
2729         if (!__id3tag_parse_PIC_format(pInfo, pTagVal, &offset))
2730                 debug_msg(RELEASE, "PIC is not valid\n");
2731
2732         __id3tag_parse_APIC_pictype(pInfo, pTagVal, &offset);
2733         __id3tag_parse_APIC_desc(pInfo, pTagVal, nTagLen, pCharSet, &offset);
2734         __id3tag_parse_APIC_picture(pInfo, pTagVal, nTagLen, &offset);
2735
2736         debug_fleave(RELEASE);
2737 }
2738
2739 static bool _mm_file_id3tag_parse_APIC(AvFileContentInfo *pInfo, unsigned char *pTagVal, int nTagLen, const char *pCharSet)
2740 {
2741         int offset = 0;
2742
2743         debug_fenter(RELEASE);
2744
2745         if (!__id3tag_parse_APIC_mimetype(pInfo, pTagVal, nTagLen, &offset)) {
2746                 debug_msg(RELEASE, "APIC is not valid\n");
2747                 return false;
2748         }
2749
2750         __id3tag_parse_APIC_pictype(pInfo, pTagVal, &offset);
2751         __id3tag_parse_APIC_desc(pInfo, pTagVal, nTagLen, pCharSet, &offset);
2752         __id3tag_parse_APIC_picture(pInfo, pTagVal, nTagLen, &offset);
2753
2754         debug_fleave(RELEASE);
2755
2756         return true;
2757 }
2758
2759 static char *_mm_file_string_convert_v224(const char *strTag, int nTagLen, const int nEncodingType, const char *strCharSet, int *npStrLen)
2760 {
2761         char *new_tag = NULL;
2762
2763         *npStrLen = 0;
2764
2765         if (nEncodingType == AV_ID3V2_UTF8) {
2766                 new_tag = g_strdup(strTag);
2767                 if (!new_tag)
2768                         return NULL;
2769
2770                 *npStrLen = strlen(new_tag);
2771         } else {
2772                 new_tag = mmfile_string_convert((const char *)strTag, nTagLen, "UTF-8", strCharSet, NULL, (unsigned int *)npStrLen);
2773         }
2774
2775         return new_tag;
2776 }
2777
2778 EXPORT_API
2779 bool mm_file_id3tag_parse_v110(AvFileContentInfo *pInfo,  unsigned char *buffer)
2780 {
2781         const char *locale = MMFileUtilGetLocale();
2782         char *pFullStr = NULL;
2783
2784         debug_msg(RELEASE, "ID3tag v110--------------------------------------------------------------\n");
2785
2786         if (pInfo->tagV2Info.bTitleMarked == false) {
2787                 pFullStr = mmfile_string_convert((const char *)&buffer[3], MP3_ID3_TITLE_LENGTH, "UTF-8", locale, NULL, (unsigned int *)&pInfo->titleLen);
2788                 if (pFullStr != NULL) {
2789                         pInfo->pTitle = rtrimN(pFullStr);
2790                         free(pFullStr);
2791                 }
2792
2793                 debug_msg(RELEASE, "pInfo->pTitle returned =(%s), pInfo->titleLen(%d)\n", pInfo->pTitle, pInfo->titleLen);
2794         }
2795
2796         if (pInfo->tagV2Info.bArtistMarked == false) {
2797                 pFullStr = mmfile_string_convert((const char *)&buffer[33], MP3_ID3_ARTIST_LENGTH, "UTF-8", locale, NULL, (unsigned int *)&pInfo->artistLen);
2798                 if (pFullStr != NULL) {
2799                         pInfo->pArtist = rtrimN(pFullStr);
2800                         free(pFullStr);
2801                 }
2802
2803                 debug_msg(RELEASE, "pInfo->pArtist returned =(%s), pInfo->artistLen(%d)\n", pInfo->pArtist, pInfo->artistLen);
2804         }
2805
2806         if (pInfo->tagV2Info.bAlbumMarked == false) {
2807                 pFullStr = mmfile_string_convert((const char *)&buffer[63], MP3_ID3_ALBUM_LENGTH, "UTF-8", locale, NULL, (unsigned int *)&pInfo->albumLen);
2808                 if (pFullStr != NULL) {
2809                         pInfo->pAlbum = rtrimN(pFullStr);
2810                         free(pFullStr);
2811                 }
2812
2813                 debug_msg(RELEASE, "pInfo->pAlbum returned =(%s), pInfo->albumLen(%d)\n", pInfo->pAlbum, pInfo->albumLen);
2814         }
2815
2816         if (pInfo->tagV2Info.bYearMarked == false) {
2817
2818                 pInfo->pYear = mmfile_string_convert((const char *)&buffer[93], MP3_ID3_YEAR_LENGTH, "UTF-8", locale, NULL, (unsigned int *)&pInfo->yearLen);
2819
2820                 debug_msg(RELEASE, "pInfo->pYear returned =(%s), pInfo->yearLen(%d)\n", pInfo->pYear, pInfo->yearLen);
2821
2822                 if (pInfo->pYear == NULL) {     /*Use same logic with ffmpeg*/
2823                         pInfo->pYear = get_string((const char *)&buffer[93], MP3_ID3_YEAR_LENGTH, (int *)&pInfo->yearLen);
2824                         debug_msg(RELEASE, "pInfo->pYear returned =(%s), pInfo->yearLen(%d)\n", pInfo->pYear, pInfo->yearLen);
2825                 }
2826         }
2827
2828         if (pInfo->tagV2Info.bDescriptionMarked == false) {
2829                 pInfo->pComment = mmfile_string_convert((const char *)&buffer[97], MP3_ID3_DESCRIPTION_LENGTH, "UTF-8", locale, NULL, (unsigned int *)&pInfo->commentLen);
2830                 debug_msg(RELEASE, "pInfo->pComment returned =(%s), pInfo->commentLen(%d)\n", pInfo->pComment, pInfo->commentLen);
2831
2832                 if (pInfo->pComment == NULL) {  /*Use same logic with ffmpeg*/
2833                         pInfo->pComment = get_string((const char *)&buffer[97], MP3_ID3_DESCRIPTION_LENGTH, (int *)&pInfo->commentLen);
2834                         debug_msg(RELEASE, "pInfo->pComment returned =(%s), pInfo->commentLen(%d)\n", pInfo->pComment, pInfo->commentLen);
2835                 }
2836         }
2837
2838         if (pInfo->tagV2Info.bTrackNumMarked == false) {
2839                 pInfo->pTrackNum = mmfile_malloc(5);
2840                 if (pInfo->pTrackNum != NULL) {
2841                         pInfo->pTrackNum[4] = 0;
2842                         snprintf(pInfo->pTrackNum, 4, "%04d", (int)buffer[126]);
2843                         pInfo->tracknumLen = strlen(pInfo->pTrackNum);
2844
2845                         debug_msg(RELEASE, "pInfo->pTrackNum returned =(%s), pInfo->tracknumLen(%d)\n", pInfo->pTrackNum, pInfo->tracknumLen);
2846                 }
2847         }
2848
2849         if (pInfo->tagV2Info.bGenreMarked == false) {
2850                 pInfo->genre = buffer[127];
2851                 debug_msg(RELEASE, "pInfo->genre returned genre number (%d)\n", pInfo->genre);
2852         }
2853
2854         return true;
2855 }
2856
2857 EXPORT_API
2858 bool mm_file_id3tag_parse_v222(AvFileContentInfo *pInfo, unsigned char *buffer)
2859 {
2860         unsigned long taglen = 0;
2861         unsigned long needToloopv2taglen;
2862         unsigned long oneFrameLen = 0;
2863         unsigned long v2numOfFrames = 0;
2864         unsigned long curPos = 0;
2865         char CompTmp[4];
2866         unsigned char *pExtContent = NULL;
2867         unsigned long purelyFramelen = 0;
2868         unsigned int encodingOffSet = 0;
2869         int realCpyFrameNum = 0, tmp = 0;
2870
2871         int textEncodingType = 0;
2872
2873         char **charset_array = NULL;
2874
2875         make_characterset_array(&charset_array);
2876
2877         init_content_info(pInfo);
2878
2879         taglen = pInfo->tagV2Info.tagLen;
2880         needToloopv2taglen = taglen - MP3_TAGv2_HEADER_LEN;
2881         curPos = MP3_TAGv2_HEADER_LEN;
2882
2883         debug_msg(RELEASE, "ID3tag v222--------------------------------------------------------------\n");
2884
2885         if (needToloopv2taglen - MP3_TAGv2_22_TXT_HEADER_LEN > MP3_TAGv2_22_TXT_HEADER_LEN) {
2886                 v2numOfFrames = 1;
2887                 while (needToloopv2taglen > MP3_TAGv2_22_TXT_HEADER_LEN) {
2888                         if ((buffer[curPos] < '0' || buffer[curPos] > 'Z') || (buffer[curPos + 1] < '0' || buffer[curPos + 1] > 'Z')
2889                             || (buffer[curPos + 2] < '0' || buffer[curPos + 2] > 'Z'))
2890                                 break;
2891
2892                         memcpy(CompTmp, &buffer[curPos], 3);
2893
2894                         CompTmp[3] = 0;
2895                         oneFrameLen = MP3_TAGv2_22_TXT_HEADER_LEN;
2896                         oneFrameLen += (unsigned long)buffer[3 + curPos] << 16 | (unsigned long)buffer[4 + curPos] << 8
2897                                                 | (unsigned long)buffer[5 + curPos];
2898                         if (oneFrameLen > taglen - curPos)
2899                                 break;
2900                         purelyFramelen = oneFrameLen - MP3_TAGv2_22_TXT_HEADER_LEN;
2901                         curPos += MP3_TAGv2_22_TXT_HEADER_LEN;
2902
2903                         if (oneFrameLen > MP3_TAGv2_22_TXT_HEADER_LEN && purelyFramelen <= taglen - curPos) {
2904                                 curPos += purelyFramelen;
2905
2906                                 if (buffer[curPos - purelyFramelen] == 0x00) {
2907                                         encodingOffSet = 1;
2908                                         textEncodingType = AV_ID3V2_ISO_8859;
2909                                 } else if (buffer[curPos - purelyFramelen] == 0x01) {
2910                                         encodingOffSet = 1;
2911                                         textEncodingType = AV_ID3V2_UTF16;
2912                                 }
2913
2914                                 /*in order to deliver valid string to MP */
2915                                 while ((buffer[curPos - purelyFramelen + encodingOffSet] < 0x20) && (encodingOffSet < purelyFramelen))
2916                                         encodingOffSet++;
2917
2918                                 if (encodingOffSet < purelyFramelen) {
2919                                         realCpyFrameNum = purelyFramelen - encodingOffSet;
2920                                         mmfile_free(pExtContent);
2921                                         pExtContent = mmfile_malloc(realCpyFrameNum + 3);
2922
2923                                         if (pExtContent == NULL) {
2924                                                 debug_error(DEBUG, "out of memory for pExtContent\n");
2925                                                 continue;
2926                                         }
2927
2928                                         memset(pExtContent, '\0', realCpyFrameNum + 3);
2929
2930                                         memcpy(pExtContent, &buffer[curPos - purelyFramelen + encodingOffSet], purelyFramelen - encodingOffSet);
2931
2932                                         if (realCpyFrameNum > 0) {
2933                                                 if (strncmp((char *)CompTmp, "TT2", 3) == 0 && pInfo->tagV2Info.bTitleMarked == false) {
2934                                                         pInfo->pTitle = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->titleLen);
2935                                                         debug_msg(RELEASE, "pInfo->pTitle returned = (%s), pInfo->titleLen(%d)\n", pInfo->pTitle, pInfo->titleLen);
2936                                                         pInfo->tagV2Info.bTitleMarked = true;
2937                                                 } else if (strncmp((char *)CompTmp, "TP1", 3) == 0 && pInfo->tagV2Info.bArtistMarked == false) {
2938                                                         pInfo->pArtist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->artistLen);
2939                                                         debug_msg(RELEASE, "pInfo->pArtist returned = (%s), pInfo->artistLen(%d)\n", pInfo->pArtist, pInfo->artistLen);
2940                                                         pInfo->tagV2Info.bArtistMarked = true;
2941                                                 } else if (strncmp((char *)CompTmp, "TP2", 3) == 0 && pInfo->tagV2Info.bAlbum_ArtistMarked == false) {
2942                                                         pInfo->pAlbum_Artist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->album_artistLen);
2943                                                         debug_msg(RELEASE, "pInfo->pAlbum_Artist returned = (%s), pInfo->album_artistLen(%d)\n", pInfo->pAlbum_Artist, pInfo->album_artistLen);
2944                                                         pInfo->tagV2Info.bAlbum_ArtistMarked = true;
2945                                                 } else if (strncmp((char *)CompTmp, "TP3", 3) == 0 && pInfo->tagV2Info.bConductorMarked == false) {
2946                                                         pInfo->pConductor = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->conductorLen);
2947                                                         debug_msg(RELEASE, "pInfo->pConductor returned = (%s), pInfo->conductorLen(%d)\n", pInfo->pConductor, pInfo->conductorLen);
2948                                                         pInfo->tagV2Info.bConductorMarked = true;
2949                                                 } else if (strncmp((char *)CompTmp, "TAL", 3) == 0 && pInfo->tagV2Info.bAlbumMarked == false) {
2950                                                         pInfo->pAlbum = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->albumLen);
2951                                                         debug_msg(RELEASE, "pInfo->pAlbum returned = (%s), pInfo->albumLen(%d)\n", pInfo->pAlbum, pInfo->albumLen);
2952                                                         pInfo->tagV2Info.bAlbumMarked = true;
2953                                                 } else if (strncmp((char *)CompTmp, "TYE", 3) == 0 && pInfo->tagV2Info.bYearMarked == false) {
2954                                                         pInfo->pYear = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->yearLen);
2955                                                         debug_msg(RELEASE, "pInfo->pYear returned = (%s), pInfo->yearLen(%d)\n", pInfo->pYear, pInfo->yearLen);
2956                                                         pInfo->tagV2Info.bYearMarked = true;
2957                                                 } else if (strncmp((char *)CompTmp, "COM", 3) == 0 && pInfo->tagV2Info.bDescriptionMarked == false) {
2958                                                         /*skip language data! */
2959                                                         if (realCpyFrameNum > 4) {
2960                                                                 realCpyFrameNum -= 4;
2961                                                                 tmp = 4;
2962
2963                                                                 /*pExtContent[tmp+1] value should't have encoding value */
2964                                                                 if (pExtContent[tmp] > 0x20 && (pExtContent[tmp - 1] == 0x00 || pExtContent[tmp - 1] == 0x01)) {
2965                                                                         if (pExtContent[tmp - 1] == 0x00)
2966                                                                                 textEncodingType = AV_ID3V2_ISO_8859;
2967                                                                         else
2968                                                                                 textEncodingType = AV_ID3V2_UTF16;
2969
2970                                                                         pInfo->pComment = mmfile_string_convert((char *)&pExtContent[tmp], realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->commentLen);
2971                                                                         debug_msg(RELEASE, "pInfo->pComment returned = (%s), pInfo->commentLen(%d)\n", pInfo->pComment, pInfo->commentLen);
2972                                                                         pInfo->tagV2Info.bDescriptionMarked = true;
2973                                                                 } else {
2974                                                                         debug_msg(RELEASE, "mmf_file_id3tag_parse_v222: failed to get Comment Info tmp(%d), purelyFramelen - encodingOffSet(%lu)\n", tmp, purelyFramelen - encodingOffSet);
2975                                                                 }
2976                                                         } else {
2977                                                                 debug_msg(RELEASE, "mmf_file_id3tag_parse_v222: Description info too small to parse realCpyFrameNum(%d)\n", realCpyFrameNum);
2978                                                         }
2979                                                         tmp = 0;
2980
2981                                                 } else if (strncmp((char *)CompTmp, "TCO", 3) == 0 && pInfo->tagV2Info.bGenreMarked == false) {
2982                                                         pInfo->pGenre = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->genreLen);
2983                                                         debug_msg(RELEASE, "pInfo->pGenre returned = (%s), pInfo->genreLen(%d)\n", pInfo->pGenre, pInfo->genreLen);
2984                                                         _mm_file_id3tag_add_bracket_at_genre(&pInfo->pGenre, pInfo->genreLen);
2985                                                         pInfo->tagV2Info.bGenreMarked = true;
2986                                                 } else if (strncmp((char *)CompTmp, "TRK", 3) == 0 && pInfo->tagV2Info.bTrackNumMarked == false) {
2987                                                         pInfo->pTrackNum = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->tracknumLen);
2988                                                         debug_msg(RELEASE, "pInfo->pTrackNum returned = (%s), pInfo->tracknumLen(%d)\n", pInfo->pTrackNum, pInfo->tracknumLen);
2989                                                         pInfo->tagV2Info.bTrackNumMarked = true;
2990                                                 } else if (strncmp((char *)CompTmp, "TEN", 3) == 0 && pInfo->tagV2Info.bEncByMarked == false) {
2991                                                         pInfo->pEncBy = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->encbyLen);
2992                                                         debug_msg(RELEASE, "pInfo->pEncBy returned = (%s), pInfo->encbyLen(%d)\n", pInfo->pEncBy, pInfo->encbyLen);
2993                                                         pInfo->tagV2Info.bEncByMarked = true;
2994                                                 } else if (strncmp((char *)CompTmp, "WXX", 3) == 0 && pInfo->tagV2Info.bURLMarked == false) {
2995                                                         if (realCpyFrameNum > 4) {
2996                                                                 /*skip language data! */
2997                                                                 realCpyFrameNum -= 4;
2998                                                                 tmp = 4;
2999
3000                                                                 /*pExtContent[tmp+1] value should't have null value */
3001                                                                 if (pExtContent[tmp] > 0x20 && (pExtContent[tmp - 1] == 0x00 || pExtContent[tmp - 1] == 0x01)) {
3002                                                                         if (pExtContent[tmp - 1] == 0x00)
3003                                                                                 textEncodingType = AV_ID3V2_ISO_8859;
3004                                                                         else
3005                                                                                 textEncodingType = AV_ID3V2_UTF16;
3006
3007                                                                         pInfo->pURL = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->urlLen);
3008                                                                         debug_msg(RELEASE, "pInfo->pURL returned = (%s), pInfo->urlLen(%d)\n", pInfo->pURL, pInfo->urlLen);
3009                                                                         pInfo->tagV2Info.bURLMarked = true;
3010                                                                 } else {
3011                                                                         debug_msg(RELEASE, "mmf_file_id3tag_parse_v222: failed to get URL Info tmp(%d), purelyFramelen - encodingOffSet(%lu)\n", tmp, purelyFramelen - encodingOffSet);
3012                                                                 }
3013                                                         } else {
3014                                                                 debug_msg(RELEASE, "mmf_file_id3tag_parse_v222: URL info too small to parse realCpyFrameNum(%d)\n", realCpyFrameNum);
3015                                                         }
3016                                                         tmp = 0;
3017                                                 } else if (strncmp((char *)CompTmp, "TCR", 3) == 0 && pInfo->tagV2Info.bCopyRightMarked == false) {
3018                                                         pInfo->pCopyright = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->copyrightLen);
3019                                                         debug_msg(RELEASE, "pInfo->pCopyright returned = (%s), pInfo->copyrightLen(%d)\n", pInfo->pCopyright, pInfo->copyrightLen);
3020                                                         pInfo->tagV2Info.bCopyRightMarked = true;
3021                                                 } else if (strncmp((char *)CompTmp, "TOA", 3) == 0 && pInfo->tagV2Info.bOriginArtistMarked == false) {
3022                                                         pInfo->pOriginArtist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->originartistLen);
3023                                                         debug_msg(RELEASE, "pInfo->pOriginArtist returned = (%s), pInfo->originartistLen(%d)\n", pInfo->pOriginArtist, pInfo->originartistLen);
3024                                                         pInfo->tagV2Info.bOriginArtistMarked = true;
3025                                                 } else if (strncmp((char *)CompTmp, "TCM", 3) == 0 && pInfo->tagV2Info.bComposerMarked == false) {
3026                                                         pInfo->pComposer = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->composerLen);
3027                                                         debug_msg(RELEASE, "pInfo->pComposer returned = (%s), pInfo->originartistLen(%d)\n", pInfo->pComposer, pInfo->composerLen);
3028                                                         pInfo->tagV2Info.bComposerMarked = true;
3029                                                 } else if (strncmp((char *)CompTmp, "TRD", 3) == 0 && pInfo->tagV2Info.bRecDateMarked == false) {
3030                                                         pInfo->pRecDate = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->recdateLen);
3031                                                         debug_msg(RELEASE, "pInfo->pRecDate returned = (%s), pInfo->recdateLen(%d)\n", pInfo->pRecDate, pInfo->recdateLen);
3032                                                         pInfo->tagV2Info.bRecDateMarked = true;
3033                                                 } else if (strncmp((char *)CompTmp, "PIC", 3) == 0 && pInfo->tagV2Info.bImageMarked == false && realCpyFrameNum <= 2000000) {
3034                                                         debug_msg(DEBUG, "text encoding %d \n", textEncodingType);
3035                                                         _mm_file_id3tag_parse_PIC(pInfo, pExtContent, realCpyFrameNum, (const char*)charset_array[textEncodingType]);
3036                                                         pInfo->tagV2Info.bImageMarked = true;
3037                                                 }
3038                                         }
3039
3040                                 }
3041                         } else {
3042                                 curPos += purelyFramelen;
3043                                 if (purelyFramelen != 0)
3044                                         needToloopv2taglen = MP3_TAGv2_22_TXT_HEADER_LEN;
3045                         }
3046
3047                         mmfile_free(pExtContent);
3048                         memset(CompTmp, 0, 4);
3049                         if (curPos < taglen) {
3050                                 needToloopv2taglen -= oneFrameLen;
3051                                 v2numOfFrames++;
3052                         } else
3053                                 needToloopv2taglen = MP3_TAGv2_22_TXT_HEADER_LEN;
3054                         oneFrameLen = 0;
3055                         encodingOffSet = 0;
3056                         realCpyFrameNum = 0;
3057                         textEncodingType = 0;
3058                         purelyFramelen = 0;
3059
3060                 }
3061         }
3062
3063         release_characterset_array(charset_array);
3064
3065         if (taglen) {
3066                 return true;
3067         } else {
3068                 return false;
3069         }
3070 }
3071
3072 EXPORT_API
3073 bool mm_file_id3tag_parse_v223(AvFileContentInfo *pInfo, unsigned char *buffer)
3074 {
3075         unsigned long taglen = 0;
3076         unsigned long needToloopv2taglen;
3077         unsigned long oneFrameLen = 0;
3078         unsigned long v2numOfFrames = 0;
3079         unsigned long curPos = 0;
3080         char CompTmp[5];
3081         unsigned char *pExtContent = NULL;
3082         unsigned long purelyFramelen = 0;
3083         unsigned int encodingOffSet = 0;
3084         int realCpyFrameNum = 0,  tmp = 0;
3085         unsigned int textEncodingType = 0;
3086         char **charset_array = NULL;
3087
3088         make_characterset_array(&charset_array);
3089
3090         init_content_info(pInfo);
3091
3092         taglen = pInfo->tagV2Info.tagLen;
3093         needToloopv2taglen = taglen - MP3_TAGv2_HEADER_LEN;
3094         curPos = MP3_TAGv2_HEADER_LEN;
3095
3096         debug_msg(RELEASE, "ID3tag v223--------------------------------------------------------------\n");
3097
3098         /* check Extended Header */
3099         if (buffer[5] & 0x40) {
3100                 /* if extended header exists, skip it*/
3101                 int extendedHeaderLen = (unsigned long)buffer[10] << 21 | (unsigned long)buffer[11] << 14 | (unsigned long)buffer[12] << 7  | (unsigned long)buffer[13];
3102
3103                 debug_msg(RELEASE, "--------------- extendedHeaderLen = %d\n", extendedHeaderLen);
3104
3105                 if (extendedHeaderLen > (int)(taglen - curPos)) {
3106                         debug_error(DEBUG, "extended header too long.\n");
3107                 } else {
3108                         curPos += extendedHeaderLen;
3109                         curPos += 4;
3110                 }
3111         }
3112
3113         if (needToloopv2taglen - MP3_TAGv2_23_TXT_HEADER_LEN > MP3_TAGv2_23_TXT_HEADER_LEN) {
3114                 v2numOfFrames = 1;
3115                 while (needToloopv2taglen > MP3_TAGv2_23_TXT_HEADER_LEN) {
3116                         if ((buffer[curPos] < '0' || buffer[curPos] > 'Z') || (buffer[curPos + 1] < '0' || buffer[curPos + 1] > 'Z')
3117                             || (buffer[curPos + 2] < '0' || buffer[curPos + 2] > 'Z') || (buffer[curPos + 3] < '0' || buffer[curPos + 3] > 'Z'))
3118                                 break;
3119
3120                         memcpy(CompTmp, &buffer[curPos], 4);
3121
3122                         CompTmp[4] = 0;
3123                         oneFrameLen = MP3_TAGv2_23_TXT_HEADER_LEN;
3124                         oneFrameLen += (unsigned long)buffer[4 + curPos] << 24 | (unsigned long)buffer[5 + curPos] << 16
3125                                                 | (unsigned long)buffer[6 + curPos] << 8 | (unsigned long)buffer[7 + curPos];
3126
3127                         debug_msg(RELEASE, "----------------------------------------------------------------------------------------------------\n");
3128
3129                         if (oneFrameLen > taglen - curPos)
3130                                 break;
3131
3132                         purelyFramelen = oneFrameLen - MP3_TAGv2_23_TXT_HEADER_LEN;
3133                         curPos += MP3_TAGv2_23_TXT_HEADER_LEN;
3134
3135                         if (oneFrameLen > MP3_TAGv2_23_TXT_HEADER_LEN && purelyFramelen <= taglen - curPos) {
3136                                 curPos += purelyFramelen;
3137
3138                                 if (IS_ENCODEDBY_UTF16(buffer + (curPos - purelyFramelen))) {
3139                                         encodingOffSet = 2;
3140                                         debug_msg(RELEASE, "this text string(%s) encoded by UTF16 encodingOffSet(%d)\n", CompTmp, encodingOffSet);
3141                                         textEncodingType = AV_ID3V2_UTF16;
3142                                 } else if (IS_ENCODEDBY_UTF16_R(buffer + (curPos - purelyFramelen))) {
3143                                         encodingOffSet = 2;
3144                                         debug_msg(RELEASE, "this text string(%s) encoded by UTF16 encodingOffSet(%d)\n", CompTmp, encodingOffSet);
3145                                         textEncodingType = AV_ID3V2_UTF16_BE;
3146                                 } else if (IS_ENCODEDBY_UTF16(buffer + (curPos - purelyFramelen + 1))) {
3147                                         encodingOffSet = 3;
3148                                         debug_msg(RELEASE, "this text string(%s) encoded by UTF16 encodingOffSet(%d)\n", CompTmp, encodingOffSet);
3149                                         textEncodingType = AV_ID3V2_UTF16;
3150                                 } else if (IS_ENCODEDBY_UTF16_R(buffer + (curPos - purelyFramelen + 1))) {
3151                                         encodingOffSet = 3;
3152                                         debug_msg(RELEASE, "this text string(%s) encoded by UTF16 encodingOffSet(%d)\n", CompTmp, encodingOffSet);
3153                                         textEncodingType = AV_ID3V2_UTF16_BE;
3154                                 } else {
3155                                         if (buffer[curPos - purelyFramelen + encodingOffSet] == 0x00) {
3156                                                 debug_msg(RELEASE, "encodingOffset will be set to 1\n");
3157                                                 encodingOffSet = 1;
3158                                         } else {
3159                                                 debug_msg(RELEASE, "Finding encodingOffset\n");
3160
3161                                                 while ((buffer[curPos - purelyFramelen + encodingOffSet] < 0x20) && (encodingOffSet < purelyFramelen)) /* text string encoded by ISO-8859-1 */
3162                                                         encodingOffSet++;
3163                                         }
3164                                         textEncodingType = AV_ID3V2_ISO_8859;
3165                                         debug_msg(RELEASE, "this text string(%s) encoded by ISO-8859-1 encodingOffSet(%d)\n", CompTmp, encodingOffSet);
3166                                 }
3167
3168                                 mmfile_free(pExtContent);
3169
3170                                 if (encodingOffSet < purelyFramelen) {
3171                                         realCpyFrameNum = purelyFramelen - encodingOffSet;
3172                                         pExtContent = mmfile_malloc(realCpyFrameNum + 3);
3173
3174                                         if (pExtContent == NULL) {
3175                                                 debug_msg(DEBUG, "pExtContent malloc failed\n");
3176                                                 continue;
3177                                         }
3178
3179                                         memset(pExtContent, '\0', realCpyFrameNum + 3);
3180
3181                                         if (textEncodingType != AV_ID3V2_UTF16 && textEncodingType != AV_ID3V2_UTF16_BE) {
3182                                                 if (CompTmp[0] == 'T' || (strcmp(CompTmp, "APIC") == 0)) {
3183                                                         debug_msg(RELEASE, "get the new text ecoding type\n");
3184                                                         textEncodingType = buffer[curPos - purelyFramelen + encodingOffSet - 1];
3185                                                 }
3186                                         }
3187
3188                                         if (textEncodingType > AV_ID3V2_MAX) {
3189                                                 debug_msg(DEBUG, "WRONG ENCOIDNG TYPE [%d], FRAME[%s]\n", textEncodingType, (char *)CompTmp);
3190                                                 continue;
3191                                         }
3192
3193                                         memcpy(pExtContent, &buffer[curPos - purelyFramelen + encodingOffSet], purelyFramelen - encodingOffSet);
3194                                         if (realCpyFrameNum > 0) {
3195                                                 if (strncmp((char *)CompTmp, "TIT2", 4) == 0 && pInfo->tagV2Info.bTitleMarked == false) {
3196                                                         pInfo->pTitle = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->titleLen);
3197                                                         debug_msg(RELEASE, "pInfo->pTitle returned = (%s), pInfo->titleLen(%d)\n", pInfo->pTitle, pInfo->titleLen);
3198                                                         pInfo->tagV2Info.bTitleMarked = true;
3199
3200                                                 } else if (strncmp((char *)CompTmp, "TPE1", 4) == 0 && pInfo->tagV2Info.bArtistMarked == false) {
3201                                                         pInfo->pArtist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->artistLen);
3202                                                         debug_msg(RELEASE, "pInfo->pArtist returned = (%s), pInfo->artistLen(%d)\n", pInfo->pArtist, pInfo->artistLen);
3203                                                         pInfo->tagV2Info.bArtistMarked = true;
3204                                                 } else if (strncmp((char *)CompTmp, "TPE2", 4) == 0 && pInfo->tagV2Info.bAlbum_ArtistMarked == false) {
3205                                                         pInfo->pAlbum_Artist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->album_artistLen);
3206                                                         debug_msg(RELEASE, "pInfo->pAlbum_Artist returned = (%s), pInfo->album_artistLen(%d)\n", pInfo->pAlbum_Artist, pInfo->album_artistLen);
3207                                                         pInfo->tagV2Info.bAlbum_ArtistMarked = true;
3208                                                 } else if (strncmp((char *)CompTmp, "TPE3", 4) == 0 && pInfo->tagV2Info.bConductorMarked == false) {
3209                                                         pInfo->pConductor = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->conductorLen);
3210                                                         debug_msg(RELEASE, "pInfo->pConductor returned = (%s), pInfo->conductorLen(%d)\n", pInfo->pConductor, pInfo->conductorLen);
3211                                                         pInfo->tagV2Info.bConductorMarked = true;
3212                                                 } else if (strncmp((char *)CompTmp, "TALB", 4) == 0 && pInfo->tagV2Info.bAlbumMarked == false) {
3213                                                         pInfo->pAlbum = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->albumLen);
3214                                                         debug_msg(RELEASE, "pInfo->pAlbum returned = (%s), pInfo->albumLen(%d)\n", pInfo->pAlbum, pInfo->albumLen);
3215                                                         pInfo->tagV2Info.bAlbumMarked = true;
3216                                                 } else if (strncmp((char *)CompTmp, "TYER", 4) == 0 && pInfo->tagV2Info.bYearMarked == false) {
3217                                                         pInfo->pYear = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->yearLen);
3218                                                         debug_msg(RELEASE, "pInfo->pYear returned = (%s), pInfo->yearLen(%d)\n", pInfo->pYear, pInfo->yearLen);
3219                                                         pInfo->tagV2Info.bYearMarked = true;
3220                                                 } else if (strncmp((char *)CompTmp, "COMM", 4) == 0 && pInfo->tagV2Info.bDescriptionMarked == false) {
3221                                                         if (realCpyFrameNum > 3) {
3222                                                                 realCpyFrameNum -= 3;
3223                                                                 tmp = 3;
3224
3225                                                                 /*pExtContent[tmp+1] value should't have encoding value */
3226                                                                 if (pExtContent[tmp] == 0x00 || pExtContent[tmp] == 0xFF || pExtContent[tmp] == 0xFE) {
3227                                                                         if ((IS_ENCODEDBY_UTF16(pExtContent + tmp) || IS_ENCODEDBY_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 2) {
3228                                                                                 while ((NEWLINE_OF_UTF16(pExtContent + tmp) || NEWLINE_OF_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 4) {
3229                                                                                         realCpyFrameNum -= 4;
3230                                                                                         tmp += 4;
3231                                                                                 }
3232
3233                                                                                 if (IS_ENCODEDBY_UTF16(pExtContent + tmp) && (realCpyFrameNum > 2)) {
3234                                                                                         realCpyFrameNum -= 2;
3235                                                                                         tmp += 2;
3236                                                                                         textEncodingType = AV_ID3V2_UTF16;
3237                                                                                 } else if (IS_ENCODEDBY_UTF16_R(pExtContent + tmp) && (realCpyFrameNum > 2)) {
3238                                                                                         realCpyFrameNum -= 2;
3239                                                                                         tmp += 2;
3240                                                                                         textEncodingType = AV_ID3V2_UTF16_BE;
3241                                                                                 } else if (IS_ENCODEDBY_UTF16(pExtContent + tmp + 1) && (realCpyFrameNum > 3)) {
3242                                                                                         realCpyFrameNum -= 3;
3243                                                                                         tmp += 3;
3244                                                                                         textEncodingType = AV_ID3V2_UTF16;
3245                                                                                 } else if (IS_ENCODEDBY_UTF16_R(pExtContent + tmp + 1)  && (realCpyFrameNum > 3)) {
3246                                                                                         realCpyFrameNum -= 3;
3247                                                                                         tmp += 3;
3248                                                                                         textEncodingType = AV_ID3V2_UTF16_BE;
3249                                                                                 } else {
3250                                                                                         debug_msg(RELEASE, "pInfo->pComment Never Get Here!!\n");
3251                                                                                 }
3252                                                                         } else {
3253                                                                                 while ((pExtContent[tmp] < 0x20) && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
3254                                                                                         realCpyFrameNum--;
3255                                                                                         tmp++;
3256                                                                                 }
3257                                                                                 textEncodingType = AV_ID3V2_ISO_8859;
3258                                                                         }
3259
3260                                                                         debug_msg(RELEASE, "tmp(%d) textEncodingType(%d), realCpyFrameNum(%d)\n", tmp, textEncodingType, realCpyFrameNum);
3261                                                                         pInfo->pComment = mmfile_string_convert((const char *)&pExtContent[tmp], realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->commentLen);
3262                                                                 } else {
3263                                                                         debug_msg(RELEASE, "failed to get Comment Info tmp(%d), purelyFramelen - encodingOffSet(%lu)\n", tmp, purelyFramelen - encodingOffSet);
3264                                                                         pInfo->commentLen = 0;
3265                                                                 }
3266                                                         } else {
3267                                                                 debug_msg(RELEASE, "Description info too small to parse realCpyFrameNum(%d)\n", realCpyFrameNum);
3268                                                                 pInfo->commentLen = 0;
3269                                                         }
3270                                                         tmp = 0;
3271
3272                                                         debug_msg(RELEASE, "pInfo->pComment returned = (%s), pInfo->commentLen(%d)\n", pInfo->pComment, pInfo->commentLen);
3273                                                         pInfo->tagV2Info.bDescriptionMarked = true;
3274                                                 } else if (strncmp((char *)CompTmp, "SYLT", 4) == 0 && pInfo->tagV2Info.bSyncLyricsMarked == false) {
3275                                                         int idx = 0;
3276                                                         int copy_len = 0;
3277                                                         int copy_start_pos = tmp;
3278                                                         AvSynclyricsInfo *synclyrics_info = NULL;
3279                                                         GList *synclyrics_info_list = NULL;
3280
3281                                                         if (realCpyFrameNum > 5) {
3282                                                                 realCpyFrameNum -= 5;
3283                                                                 tmp = 5;
3284
3285                                                                 /*pExtContent[tmp+1] value should't have encoding value */
3286                                                                 if (pExtContent[tmp] == 0x00 || pExtContent[tmp] == 0xFF || pExtContent[tmp] == 0xFE) {
3287                                                                         if ((IS_ENCODEDBY_UTF16(pExtContent + tmp) || IS_ENCODEDBY_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 2) {
3288                                                                                 while ((NEWLINE_OF_UTF16(pExtContent + tmp) || NEWLINE_OF_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 4) {
3289                                                                                         realCpyFrameNum -= 4;
3290                                                                                         tmp += 4;
3291                                                                                 }
3292
3293                                                                                 if (IS_ENCODEDBY_UTF16(pExtContent + tmp) && (realCpyFrameNum > 2)) {
3294                                                                                         realCpyFrameNum -= 2;
3295                                                                                         tmp += 2;
3296                                                                                         textEncodingType = AV_ID3V2_UTF16;
3297                                                                                 } else if (IS_ENCODEDBY_UTF16_R(pExtContent + tmp) && (realCpyFrameNum > 2)) {
3298                                                                                         realCpyFrameNum -= 2;
3299                                                                                         tmp += 2;
3300                                                                                         textEncodingType = AV_ID3V2_UTF16_BE;
3301                                                                                 } else if (IS_ENCODEDBY_UTF16(pExtContent + tmp + 1) && (realCpyFrameNum > 3)) {
3302                                                                                         realCpyFrameNum -= 3;
3303                                                                                         tmp += 3;
3304                                                                                         textEncodingType = AV_ID3V2_UTF16;
3305                                                                                 } else if (IS_ENCODEDBY_UTF16_R(pExtContent + tmp + 1)  && (realCpyFrameNum > 3)) {
3306                                                                                         realCpyFrameNum -= 3;
3307                                                                                         tmp += 3;
3308                                                                                         textEncodingType = AV_ID3V2_UTF16_BE;
3309                                                                                 } else {
3310                                                                                         debug_msg(RELEASE, "pInfo->pSyncLyrics Never Get Here!!\n");
3311                                                                                 }
3312                                                                         } else {
3313                                                                                 while ((pExtContent[tmp] < 0x20) && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
3314                                                                                         realCpyFrameNum--;
3315                                                                                         tmp++;
3316                                                                                 }
3317                                                                                 textEncodingType = AV_ID3V2_ISO_8859;
3318                                                                         }
3319
3320                                                                         debug_msg(RELEASE, "tmp(%d) textEncodingType(%d), realCpyFrameNum(%d)\n", tmp, textEncodingType, realCpyFrameNum);
3321
3322                                                                         if (realCpyFrameNum < MMFILE_SYNC_LYRIC_INFO_MIN_LEN) {
3323                                                                                 debug_msg(RELEASE, "failed to get Synchronised lyrics Info realCpyFramNum(%d)\n", realCpyFrameNum);
3324                                                                                 pInfo->syncLyricsNum = 0;
3325                                                                         } else {
3326                                                                                 if (textEncodingType == AV_ID3V2_UTF16) {
3327                                                                                         debug_warning(DEBUG, "[AV_ID3V2_UTF16] not implemented\n");
3328                                                                                 } else if (textEncodingType == AV_ID3V2_UTF16_BE) {
3329                                                                                         debug_warning(DEBUG, "[AV_ID3V2_UTF16_BE] not implemented\n");
3330                                                                                 } else {
3331                                                                                         for (idx = 0; idx < realCpyFrameNum; idx++) {
3332                                                                                                 if (pExtContent[tmp + idx] == 0x00) {
3333                                                                                                         synclyrics_info = (AvSynclyricsInfo *)malloc(sizeof(AvSynclyricsInfo));
3334
3335                                                                                                         if (synclyrics_info != NULL) {
3336                                                                                                                 if (textEncodingType == AV_ID3V2_UTF8) {
3337                                                                                                                         synclyrics_info->lyric_info = mmfile_malloc(copy_len + 1);
3338                                                                                                                         if (synclyrics_info->lyric_info != NULL) {
3339                                                                                                                                 memset(synclyrics_info->lyric_info, 0, copy_len + 1);
3340                                                                                                                                 memcpy(synclyrics_info->lyric_info, pExtContent + copy_start_pos, copy_len);
3341                                                                                                                                 synclyrics_info->lyric_info[copy_len] = '\0';
3342                                                                                                                         }
3343                                                                                                                 } else {
3344                                                                                                                         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);
3345                                                                                                                 }
3346
3347                                                                                                                 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];
3348                                                                                                                 idx += 4;
3349                                                                                                                 copy_start_pos = tmp + idx + 1;
3350                                                                                                                 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);
3351                                                                                                                 copy_len = 0;
3352                                                                                                                 synclyrics_info_list = g_list_append(synclyrics_info_list, synclyrics_info);
3353                                                                                                         }
3354                                                                                                 }
3355                                                                                                 copy_len++;
3356                                                                                         }
3357                                                                                         pInfo->pSyncLyrics = synclyrics_info_list;
3358                                                                                         pInfo->syncLyricsNum = g_list_length(pInfo->pSyncLyrics);
3359                                                                                 }
3360                                                                         }
3361                                                                 } else {
3362                                                                         debug_msg(RELEASE, "failed to get Synchronised lyrics Info tmp(%d), purelyFramelen - encodingOffSet(%lu)\n", tmp, purelyFramelen - encodingOffSet);
3363                                                                         pInfo->syncLyricsNum = 0;
3364                                                                 }
3365                                                         } else {
3366                                                                 debug_msg(RELEASE, "Synchronised lyrics too small to parse realCpyFrameNum(%d)\n", realCpyFrameNum);
3367                                                                 pInfo->syncLyricsNum = 0;
3368                                                         }
3369                                                         tmp = 0;
3370
3371                                                         //debug_msg(RELEASE, "pInfo->pSyncLyrics returned = (%s), pInfo->syncLyricsNum(%d)\n", pInfo->pSyncLyrics, pInfo->syncLyricsNum);
3372                                                         debug_msg(RELEASE, "pInfo->syncLyricsNum(%d)\n", pInfo->syncLyricsNum);
3373                                                         pInfo->tagV2Info.bSyncLyricsMarked = true;
3374                                                 } else if (strncmp((char *)CompTmp, "USLT", 4) == 0 && pInfo->tagV2Info.bUnsyncLyricsMarked == false) {
3375                                                         char *lang_info = strndup((char *)pExtContent, 3);
3376
3377                                                         if (realCpyFrameNum > 3) {
3378                                                                 realCpyFrameNum -= 3;
3379                                                                 tmp = 3;
3380
3381                                                                 /*find start of lyrics */
3382                                                                 while (1) {
3383                                                                         if (pExtContent[tmp] == 0x00) {
3384                                                                                 if (pExtContent[tmp + 1] == 0x00) {
3385                                                                                         realCpyFrameNum -= 2;
3386                                                                                         tmp += 2;
3387                                                                                 }
3388                                                                                 break;
3389                                                                         } else {
3390                                                                                 realCpyFrameNum--;
3391                                                                                 tmp++;
3392                                                                         }
3393                                                                 }
3394
3395                                                                 /*pExtContent[tmp+1] value should't have encoding value */
3396                                                                 debug_msg(RELEASE, "tpExtContent[%d] %x\n", tmp, pExtContent[tmp]);
3397
3398                                                                 if (pExtContent[tmp] == 0x00 || pExtContent[tmp] == 0xFF || pExtContent[tmp] == 0xFE) {
3399                                                                         if ((IS_ENCODEDBY_UTF16(pExtContent + tmp) || IS_ENCODEDBY_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 2) {
3400                                                                                 while ((NEWLINE_OF_UTF16(pExtContent + tmp) || NEWLINE_OF_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 4) {
3401                                                                                         realCpyFrameNum -= 4;
3402                                                                                         tmp += 4;
3403                                                                                 }
3404
3405                                                                                 if (IS_ENCODEDBY_UTF16(pExtContent + tmp) && (realCpyFrameNum > 2)) {
3406                                                                                         realCpyFrameNum -= 2;
3407                                                                                         tmp += 2;
3408                                                                                         textEncodingType = AV_ID3V2_UTF16;
3409                                                                                 } else if (IS_ENCODEDBY_UTF16_R(pExtContent + tmp) && (realCpyFrameNum > 2)) {
3410                                                                                         realCpyFrameNum -= 2;
3411                                                                                         tmp += 2;
3412                                                                                         textEncodingType = AV_ID3V2_UTF16_BE;
3413                                                                                 } else if (IS_ENCODEDBY_UTF16(pExtContent + tmp + 1) && (realCpyFrameNum > 3)) {
3414                                                                                         realCpyFrameNum -= 3;
3415                                                                                         tmp += 3;
3416                                                                                         textEncodingType = AV_ID3V2_UTF16;
3417                                                                                 } else if (IS_ENCODEDBY_UTF16_R(pExtContent + tmp + 1)  && (realCpyFrameNum > 3)) {
3418                                                                                         realCpyFrameNum -= 3;
3419                                                                                         tmp += 3;
3420                                                                                         textEncodingType = AV_ID3V2_UTF16_BE;
3421                                                                                 } else {
3422                                                                                         debug_msg(RELEASE, "pInfo->pUnsyncLyrics Never Get Here!!\n");
3423                                                                                 }
3424                                                                         } else {
3425                                                                                 while ((pExtContent[tmp] < 0x20) && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
3426                                                                                         realCpyFrameNum--;
3427                                                                                         tmp++;
3428                                                                                 }
3429                                                                                 textEncodingType = AV_ID3V2_ISO_8859;
3430                                                                         }
3431
3432                                                                         char *char_set = NULL;
3433
3434                                                                         debug_msg(RELEASE, "tmp(%d) textEncodingType(%d), realCpyFrameNum(%d)\n", tmp, textEncodingType, realCpyFrameNum);
3435
3436                                                                         if (textEncodingType == AV_ID3V2_ISO_8859) {
3437                                                                                 if (lang_info != NULL && !g_ascii_strcasecmp(lang_info, "KOR")) {
3438                                                                                         char_set = strdup("EUC-KR");
3439                                                                                 } else {
3440                                                                                         char_set = mmfile_get_charset((const char *)&pExtContent[tmp]);
3441                                                                                 }
3442                                                                                 mmfile_free(lang_info);
3443                                                                         }
3444
3445                                                                         if (char_set == NULL) {
3446                                                                                 pInfo->pUnsyncLyrics = mmfile_string_convert((const char *)&pExtContent[tmp], realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->unsynclyricsLen);
3447                                                                         } else {
3448                                                                                 pInfo->pUnsyncLyrics = mmfile_string_convert((const char *)&pExtContent[tmp], realCpyFrameNum, "UTF-8", char_set, NULL, (unsigned int *)&pInfo->unsynclyricsLen);
3449                                                                                 mmfile_free(char_set);
3450                                                                         }
3451                                                                 } else {
3452                                                                         debug_msg(RELEASE, "failed to get Unsynchronised lyrics Info tmp(%d), purelyFramelen - encodingOffSet(%lu)\n", tmp, purelyFramelen - encodingOffSet);
3453                                                                         pInfo->unsynclyricsLen = 0;
3454                                                                 }
3455                                                         } else {
3456                                                                 debug_msg(RELEASE, "Unsynchronised lyrics too small to parse realCpyFrameNum(%d)\n", realCpyFrameNum);
3457                                                                 pInfo->unsynclyricsLen = 0;
3458                                                         }
3459                                                         tmp = 0;
3460
3461                                                         debug_msg(RELEASE, "pInfo->pUnsyncLyrics returned = (%s), pInfo->unsynclyricsLen(%d)\n", pInfo->pUnsyncLyrics, pInfo->unsynclyricsLen);
3462                                                         pInfo->tagV2Info.bUnsyncLyricsMarked = true;
3463                                                         mmfile_free(lang_info);
3464                                                 } else if (strncmp((char *)CompTmp, "TCON", 4) == 0 && pInfo->tagV2Info.bGenreMarked == false) {
3465                                                         pInfo->pGenre = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->genreLen);
3466                                                         debug_msg(RELEASE, "pInfo->pGenre returned = (%s), pInfo->genreLen(%d)\n", pInfo->pGenre, pInfo->genreLen);
3467                                                         _mm_file_id3tag_add_bracket_at_genre(&pInfo->pGenre, pInfo->genreLen);
3468                                                         pInfo->tagV2Info.bGenreMarked = true;
3469                                                 } else if (strncmp((char *)CompTmp, "TRCK", 4) == 0 && pInfo->tagV2Info.bTrackNumMarked == false) {
3470                                                         pInfo->pTrackNum = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->tracknumLen);
3471                                                         debug_msg(RELEASE, "pInfo->pTrackNum returned = (%s), pInfo->tracknumLen(%d)\n", pInfo->pTrackNum, pInfo->tracknumLen);
3472                                                         pInfo->tagV2Info.bTrackNumMarked = true;
3473                                                 } else if (strncmp((char *)CompTmp, "TPOS", 4) == 0 && pInfo->tagV2Info.bPartOfASetMarked == false) {
3474                                                         pInfo->pPartOfASet = mmfile_string_convert((const char*)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int*)&pInfo->partofsetLen);
3475                                                         debug_msg(RELEASE, "pInfo->pPartOfASet returned = (%s), pInfo->partofsetLen(%d)\n", pInfo->pPartOfASet, pInfo->partofsetLen);
3476                                                         pInfo->tagV2Info.bPartOfASetMarked = true;
3477                                                 } else if (strncmp((char *)CompTmp, "TENC", 4) == 0 && pInfo->tagV2Info.bEncByMarked == false) {
3478                                                         pInfo->pEncBy = mmfile_string_convert((char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->encbyLen);
3479                                                         debug_msg(RELEASE, "pInfo->pEncBy returned = (%s), pInfo->encbyLen(%d)\n", pInfo->pEncBy, pInfo->encbyLen);
3480                                                         pInfo->tagV2Info.bEncByMarked = true;
3481                                                 } else if (strncmp((char *)CompTmp, "WXXX", 4) == 0 && pInfo->tagV2Info.bURLMarked == false) {
3482                                                         pInfo->pURL = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->urlLen);
3483                                                         debug_msg(RELEASE, "pInfo->pURL returned = (%s), pInfo->urlLen(%d)\n", pInfo->pURL, pInfo->urlLen);
3484                                                         pInfo->tagV2Info.bURLMarked = true;
3485                                                 } else if (strncmp((char *)CompTmp, "TCOP", 4) == 0 && pInfo->tagV2Info.bCopyRightMarked == false) {
3486                                                         pInfo->pCopyright = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->copyrightLen);
3487                                                         debug_msg(RELEASE, "pInfo->pCopyright returned = (%s), pInfo->copyrightLen(%d)\n", pInfo->pCopyright, pInfo->copyrightLen);
3488                                                         pInfo->tagV2Info.bCopyRightMarked = true;
3489                                                 } else if (strncmp((char *)CompTmp, "TOPE", 4) == 0 && pInfo->tagV2Info.bOriginArtistMarked == false) {
3490                                                         pInfo->pOriginArtist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->originartistLen);
3491                                                         debug_msg(RELEASE, "pInfo->pOriginArtist returned = (%s), pInfo->originartistLen(%d)\n", pInfo->pOriginArtist, pInfo->originartistLen);
3492                                                         pInfo->tagV2Info.bOriginArtistMarked = true;
3493                                                 } else if (strncmp((char *)CompTmp, "TCOM", 4) == 0 && pInfo->tagV2Info.bComposerMarked == false) {
3494                                                         pInfo->pComposer = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->composerLen);
3495                                                         debug_msg(RELEASE, "pInfo->pComposer returned = (%s), pInfo->composerLen(%d)\n", pInfo->pComposer, pInfo->composerLen);
3496                                                         pInfo->tagV2Info.bComposerMarked = true;
3497                                                 } else if (strncmp((char *)CompTmp, "TRDA", 4) == 0 && pInfo->tagV2Info.bRecDateMarked == false) {
3498                                                         pInfo->pRecDate = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->recdateLen);
3499                                                         debug_msg(RELEASE, "pInfo->pRecDate returned = (%s), pInfo->recdateLen(%d)\n", pInfo->pRecDate, pInfo->recdateLen);
3500                                                         pInfo->tagV2Info.bRecDateMarked = true;
3501                                                 } else if (strncmp((char *)CompTmp, "APIC", 4) == 0 && pInfo->tagV2Info.bImageMarked == false && realCpyFrameNum <= 2000000) {
3502                                                         debug_msg(DEBUG, "text encoding %d \n", textEncodingType);
3503                                                         if (!_mm_file_id3tag_parse_APIC(pInfo, pExtContent, realCpyFrameNum, (const char*)charset_array[textEncodingType]))
3504                                                                 continue;
3505                                                         pInfo->tagV2Info.bImageMarked = true;
3506                                                 } else {
3507                                                         debug_msg(RELEASE, "CompTmp(%s) This Frame ID currently not Supports!!\n", CompTmp);
3508                                                 }
3509                                         }
3510
3511                                 } else {
3512                                         debug_msg(RELEASE, "All of the pExtContent Values are NULL\n");
3513                                 }
3514                         } else {
3515                                 curPos += purelyFramelen;
3516                                 if (purelyFramelen != 0)
3517                                         needToloopv2taglen = MP3_TAGv2_23_TXT_HEADER_LEN;
3518
3519                                 debug_msg(RELEASE, "This Frame's size is Zero! purelyFramelen(%lu)\n", purelyFramelen);
3520                         }
3521
3522                         mmfile_free(pExtContent);
3523                         memset(CompTmp, 0, 4);
3524
3525                         if (curPos < taglen) {
3526                                 needToloopv2taglen -= oneFrameLen;
3527                                 v2numOfFrames++;
3528                         } else
3529                                 needToloopv2taglen = MP3_TAGv2_23_TXT_HEADER_LEN;
3530                         oneFrameLen = 0;
3531                         encodingOffSet = 0;
3532                         realCpyFrameNum = 0;
3533                         textEncodingType = 0;
3534                         purelyFramelen = 0;
3535
3536                 }
3537         }
3538
3539         release_characterset_array(charset_array);
3540
3541         if (taglen)
3542                 return true;
3543         else
3544                 return false;
3545
3546 }
3547
3548 EXPORT_API
3549 bool mm_file_id3tag_parse_v224(AvFileContentInfo *pInfo, unsigned char *buffer)
3550 {
3551         unsigned long taglen = 0;
3552         unsigned long needToloopv2taglen;
3553         unsigned long oneFrameLen = 0;
3554         unsigned long v2numOfFrames = 0;
3555         unsigned long curPos = 0;
3556         char CompTmp[5];
3557         unsigned char *pExtContent = NULL;
3558         unsigned long purelyFramelen = 0;
3559         unsigned int encodingOffSet = 0;
3560         int realCpyFrameNum = 0,  tmp = 0;
3561         unsigned int textEncodingType = 0;
3562         char **charset_array = NULL;
3563
3564         make_characterset_array(&charset_array);
3565
3566         init_content_info(pInfo);
3567
3568         taglen = pInfo->tagV2Info.tagLen;
3569         needToloopv2taglen = taglen - MP3_TAGv2_HEADER_LEN;
3570         curPos = MP3_TAGv2_HEADER_LEN;
3571
3572         debug_msg(RELEASE, "ID3tag v224--------------------------------------------------------------\n");
3573
3574         /* check Extended Header */
3575         if (buffer[5] & 0x40) {
3576                 /* if extended header exists, skip it*/
3577                 int extendedHeaderLen = (unsigned long)buffer[10] << 21 | (unsigned long)buffer[11] << 14 | (unsigned long)buffer[12] << 7  | (unsigned long)buffer[13];
3578
3579                 debug_msg(RELEASE, "--------------- extendedHeaderLen = %d\n", extendedHeaderLen);
3580
3581                 if (extendedHeaderLen > (int)(taglen - curPos)) {
3582                         debug_error(DEBUG, "extended header too long.\n");
3583                 } else {
3584                         curPos += extendedHeaderLen;
3585                 }
3586         }
3587
3588         if (needToloopv2taglen - MP3_TAGv2_23_TXT_HEADER_LEN > MP3_TAGv2_23_TXT_HEADER_LEN) {
3589                 v2numOfFrames = 1;
3590                 while (needToloopv2taglen > MP3_TAGv2_23_TXT_HEADER_LEN) {
3591                         if ((buffer[curPos] < '0' || buffer[curPos] > 'Z') || (buffer[curPos + 1] < '0' || buffer[curPos + 1] > 'Z')
3592                             || (buffer[curPos + 2] < '0' || buffer[curPos + 2] > 'Z') || (buffer[curPos + 3] < '0' || buffer[curPos + 3] > 'Z'))
3593                                 break;
3594
3595                         memcpy(CompTmp, &buffer[curPos], 4);
3596
3597                         CompTmp[4] = 0;
3598                         oneFrameLen = MP3_TAGv2_23_TXT_HEADER_LEN;
3599                         oneFrameLen += (unsigned long)buffer[4 + curPos] << 21 | (unsigned long)buffer[5 + curPos] << 14
3600                                                 | (unsigned long)buffer[6 + curPos] << 7 | (unsigned long)buffer[7 + curPos];
3601                         if (oneFrameLen > taglen - curPos)
3602                                 break;
3603
3604                         purelyFramelen = oneFrameLen - MP3_TAGv2_23_TXT_HEADER_LEN;
3605                         curPos += MP3_TAGv2_23_TXT_HEADER_LEN;
3606
3607                         debug_msg(RELEASE, "-----------------------------------------------------------------------------------\n");
3608
3609                         if (oneFrameLen > MP3_TAGv2_23_TXT_HEADER_LEN && purelyFramelen <= taglen - curPos) {
3610                                 curPos += purelyFramelen;
3611
3612                                 /*in case of UTF 16 encoding */
3613                                 /*buffer+(curPos-purelyFramelen) data should '0x01' but in order to expansion, we don't accurately check the value. */
3614                                 if (IS_ENCODEDBY_UTF16(buffer + (curPos - purelyFramelen))) {
3615                                         encodingOffSet = 2;
3616                                         textEncodingType = AV_ID3V2_UTF16;
3617                                 } else if (IS_ENCODEDBY_UTF16_R(buffer + (curPos - purelyFramelen))) {
3618                                         encodingOffSet = 2;
3619                                         textEncodingType = AV_ID3V2_UTF16_BE;
3620                                 } else if (IS_ENCODEDBY_UTF16(buffer + (curPos - purelyFramelen + 1))) {
3621                                         encodingOffSet = 3;
3622                                         textEncodingType = AV_ID3V2_UTF16;
3623                                 } else if (IS_ENCODEDBY_UTF16_R(buffer + (curPos - purelyFramelen + 1))) {
3624                                         encodingOffSet = 3;
3625                                         textEncodingType = AV_ID3V2_UTF16_BE;
3626                                 } else {
3627                                         /*in case of UTF-16 BE encoding */
3628                                         if (buffer[curPos - purelyFramelen] == 0x02) {
3629                                                 encodingOffSet = 1;
3630                                                 while ((buffer[curPos - purelyFramelen + encodingOffSet] == '\0') && (encodingOffSet < purelyFramelen))
3631                                                         encodingOffSet++;/*null skip! */
3632                                                 textEncodingType = AV_ID3V2_UTF16_BE;
3633                                         }
3634                                         /*in case of UTF8 encoding */
3635                                         else if (buffer[curPos - purelyFramelen] == 0x03) {
3636                                                 encodingOffSet = 1;
3637                                                 while ((buffer[curPos - purelyFramelen + encodingOffSet] == '\0') && (encodingOffSet < purelyFramelen))
3638                                                         encodingOffSet++;/*null skip! */
3639                                                 textEncodingType = AV_ID3V2_UTF8;
3640                                         }
3641                                         /*in case of ISO-8859-1 encoding */
3642                                         else {
3643                                                 /*buffer+(curPos-purelyFramelen) data should 0x00 but in order to expansion, we don't accurately check the value. */
3644                                                 encodingOffSet = 1;
3645                                                 while ((buffer[curPos - purelyFramelen + encodingOffSet] < 0x20) && (encodingOffSet < purelyFramelen))
3646                                                         encodingOffSet++;/*less than 0x20 value skip! */
3647                                                 textEncodingType = AV_ID3V2_ISO_8859;
3648                                         }
3649                                 }
3650
3651                                 mmfile_free(pExtContent);
3652
3653                                 if (encodingOffSet < purelyFramelen) {
3654                                         realCpyFrameNum = purelyFramelen - encodingOffSet;
3655                                         pExtContent = mmfile_malloc(realCpyFrameNum + 3);
3656
3657                                         if (pExtContent == NULL) {
3658                                                 debug_error(DEBUG, "out of memoryu for id3tag parse\n");
3659                                                 continue;
3660                                         }
3661
3662                                         memset(pExtContent, '\0', realCpyFrameNum + 3);
3663
3664                                         if (textEncodingType != AV_ID3V2_UTF16 && textEncodingType != AV_ID3V2_UTF16_BE) {
3665                                                 if (CompTmp[0] == 'T' || (strcmp(CompTmp, "APIC") == 0)) {
3666                                                         debug_msg(RELEASE, "get the new text ecoding type\n");
3667                                                         textEncodingType = buffer[curPos - purelyFramelen + encodingOffSet - 1];
3668                                                 }
3669                                         }
3670
3671                                         if (textEncodingType > AV_ID3V2_MAX) {
3672                                                 debug_msg(DEBUG, "WRONG ENCOIDNG TYPE [%d], FRAME[%s]\n", textEncodingType, (char *)CompTmp);
3673                                                 continue;
3674                                         }
3675
3676                                         memcpy(pExtContent, &buffer[curPos - purelyFramelen + encodingOffSet], purelyFramelen - encodingOffSet);
3677
3678                                         if (realCpyFrameNum > 0) {
3679                                                 if (strncmp((char *)CompTmp, "TIT2", 4) == 0 && pInfo->tagV2Info.bTitleMarked == false) {
3680                                                         pInfo->pTitle = _mm_file_string_convert_v224((const char *)pExtContent, realCpyFrameNum, textEncodingType, charset_array[textEncodingType], &pInfo->titleLen);
3681                                                         debug_msg(RELEASE, "pInfo->pTitle returned = (%s), pInfo->titleLen(%d)\n", pInfo->pTitle, pInfo->titleLen);
3682                                                         pInfo->tagV2Info.bTitleMarked = true;
3683
3684                                                 } else if (strncmp((char *)CompTmp, "TPE1", 4) == 0 && pInfo->tagV2Info.bArtistMarked == false) {
3685                                                         pInfo->pArtist = _mm_file_string_convert_v224((const char *)pExtContent, realCpyFrameNum, textEncodingType, charset_array[textEncodingType], &pInfo->artistLen);
3686                                                         debug_msg(RELEASE, "pInfo->pArtist returned = (%s), pInfo->artistLen(%d)\n", pInfo->pArtist, pInfo->artistLen);
3687                                                         pInfo->tagV2Info.bArtistMarked = true;
3688                                                 } else if (strncmp((char *)CompTmp, "TPE2", 4) == 0 && pInfo->tagV2Info.bAlbum_ArtistMarked == false) {
3689                                                         pInfo->pAlbum_Artist = _mm_file_string_convert_v224((const char *)pExtContent, realCpyFrameNum, textEncodingType, charset_array[textEncodingType], &pInfo->album_artistLen);
3690                                                         debug_msg(RELEASE, "pInfo->pAlbum_Artist returned = (%s), pInfo->album_artistLen(%d)\n", pInfo->pAlbum_Artist, pInfo->album_artistLen);
3691                                                         pInfo->tagV2Info.bAlbum_ArtistMarked = true;
3692                                                 } else if (strncmp((char *)CompTmp, "TPE3", 4) == 0 && pInfo->tagV2Info.bConductorMarked == false) {
3693                                                         pInfo->pConductor = _mm_file_string_convert_v224((const char *)pExtContent, realCpyFrameNum, textEncodingType, charset_array[textEncodingType], &pInfo->conductorLen);
3694                                                         debug_msg(RELEASE, "pInfo->pConductor returned = (%s), pInfo->conductorLen(%d)\n", pInfo->pConductor, pInfo->conductorLen);
3695                                                         pInfo->tagV2Info.bConductorMarked = true;
3696                                                 } else if (strncmp((char *)CompTmp, "TALB", 4) == 0 && pInfo->tagV2Info.bAlbumMarked == false) {
3697                                                         pInfo->pAlbum = _mm_file_string_convert_v224((const char *)pExtContent, realCpyFrameNum, textEncodingType, charset_array[textEncodingType], &pInfo->albumLen);
3698                                                         debug_msg(RELEASE, "pInfo->pAlbum returned = (%s), pInfo->albumLen(%d)\n", pInfo->pAlbum, pInfo->albumLen);
3699                                                         pInfo->tagV2Info.bAlbumMarked = true;
3700                                                 } 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 */
3701                                                         pInfo->pYear = _mm_file_string_convert_v224((const char *)pExtContent, realCpyFrameNum, textEncodingType, charset_array[textEncodingType], &pInfo->yearLen);
3702                                                         debug_msg(RELEASE, "pInfo->pYear returned = (%s), pInfo->yearLen(%d)\n", pInfo->pYear, pInfo->yearLen);
3703                                                         pInfo->tagV2Info.bYearMarked = true;
3704                                                 } else if (strncmp((char *)CompTmp, "COMM", 4) == 0 && pInfo->tagV2Info.bDescriptionMarked == false) {
3705                                                         if (realCpyFrameNum > 3) {
3706                                                                 realCpyFrameNum -= 3;
3707                                                                 tmp = 3;
3708
3709                                                                 if (textEncodingType == AV_ID3V2_UTF16 || textEncodingType == AV_ID3V2_UTF16_BE) {
3710                                                                         while ((NEWLINE_OF_UTF16(pExtContent + tmp) || NEWLINE_OF_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 4) {
3711                                                                                 realCpyFrameNum -= 4;
3712                                                                                 tmp += 4;
3713                                                                         }
3714
3715                                                                         if ((IS_ENCODEDBY_UTF16(pExtContent + tmp) || IS_ENCODEDBY_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 2) {
3716                                                                                 realCpyFrameNum -= 2;
3717                                                                                 tmp += 2;
3718                                                                                 textEncodingType = AV_ID3V2_UTF16;
3719                                                                         } else {
3720                                                                                 debug_msg(RELEASE, "pInfo->pComment Never Get Here!!\n");
3721                                                                         }
3722                                                                 } else if (textEncodingType == AV_ID3V2_UTF8) {
3723                                                                         while (pExtContent[tmp] < 0x20 && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
3724                                                                                 realCpyFrameNum--;
3725                                                                                 tmp++;
3726                                                                         }
3727                                                                         textEncodingType = AV_ID3V2_UTF8;
3728                                                                 } else {
3729                                                                         while (pExtContent[tmp] < 0x20 && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
3730                                                                                 realCpyFrameNum--;
3731                                                                                 tmp++;
3732                                                                         }
3733                                                                         textEncodingType = AV_ID3V2_ISO_8859;
3734                                                                 }
3735
3736                                                                 debug_msg(RELEASE, "tmp(%d) textEncodingType(%d), realCpyFrameNum(%d)\n", tmp, textEncodingType, realCpyFrameNum);
3737
3738                                                                 pInfo->pComment = _mm_file_string_convert_v224((const char *)&pExtContent[tmp], realCpyFrameNum, textEncodingType, charset_array[textEncodingType], &pInfo->commentLen);
3739                                                         } else {
3740                                                                 debug_msg(RELEASE, "Description info too small to parse realCpyFrameNum(%d)\n", realCpyFrameNum);
3741                                                         }
3742
3743                                                         tmp = 0;
3744
3745                                                         debug_msg(RELEASE, "pInfo->pComment returned = (%s), pInfo->commentLen(%d)\n", pInfo->pComment, pInfo->commentLen);
3746                                                         pInfo->tagV2Info.bDescriptionMarked = true;
3747                                                 } else if (strncmp((char *)CompTmp, "SYLT", 4) == 0 && pInfo->tagV2Info.bSyncLyricsMarked == false) {
3748                                                         int idx = 0;
3749                                                         int copy_len = 0;
3750                                                         int copy_start_pos = tmp;
3751                                                         AvSynclyricsInfo *synclyrics_info = NULL;
3752                                                         GList *synclyrics_info_list = NULL;
3753
3754                                                         if (realCpyFrameNum > 5) {
3755                                                                 realCpyFrameNum -= 5;
3756                                                                 tmp = 5;
3757
3758                                                                 if (textEncodingType == AV_ID3V2_UTF16 || textEncodingType == AV_ID3V2_UTF16_BE) {
3759                                                                         while ((NEWLINE_OF_UTF16(pExtContent + tmp) || NEWLINE_OF_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 4) {
3760                                                                                 realCpyFrameNum -= 4;
3761                                                                                 tmp += 4;
3762                                                                         }
3763
3764                                                                         if ((IS_ENCODEDBY_UTF16(pExtContent + tmp) || IS_ENCODEDBY_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 2) {
3765                                                                                 realCpyFrameNum -= 2;
3766                                                                                 tmp += 2;
3767                                                                                 textEncodingType = AV_ID3V2_UTF16;
3768                                                                         } else {
3769                                                                                 debug_msg(RELEASE, "pInfo->pSyncLyrics Never Get Here!!\n");
3770                                                                         }
3771                                                                 } else if (textEncodingType == AV_ID3V2_UTF8) {
3772                                                                         while (pExtContent[tmp] < 0x20 && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
3773                                                                                 realCpyFrameNum--;
3774                                                                                 tmp++;
3775                                                                         }
3776                                                                         textEncodingType = AV_ID3V2_UTF8;
3777                                                                 } else {
3778                                                                         while (pExtContent[tmp] < 0x20 && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
3779                                                                                 realCpyFrameNum--;
3780                                                                                 tmp++;
3781                                                                         }
3782                                                                         textEncodingType = AV_ID3V2_ISO_8859;
3783                                                                 }
3784
3785                                                                 debug_msg(RELEASE, "tmp(%d) textEncodingType(%d), realCpyFrameNum(%d)\n", tmp, textEncodingType, realCpyFrameNum);
3786
3787                                                                 if (realCpyFrameNum < MMFILE_SYNC_LYRIC_INFO_MIN_LEN) {
3788                                                                         debug_msg(RELEASE, "failed to get Synchronised lyrics Info realCpyFramNum(%d)\n", realCpyFrameNum);
3789                                                                         pInfo->syncLyricsNum = 0;
3790                                                                 } else {
3791                                                                         if (textEncodingType == AV_ID3V2_UTF16) {
3792                                                                                 debug_warning(DEBUG, "[AV_ID3V2_UTF16] not implemented\n");
3793                                                                         } else if (textEncodingType == AV_ID3V2_UTF16_BE) {
3794                                                                                 debug_warning(DEBUG, "[AV_ID3V2_UTF16_BE] not implemented\n");
3795                                                                         } else {
3796                                                                                 for (idx = 0; idx < realCpyFrameNum; idx++) {
3797                                                                                         if (pExtContent[tmp + idx] == 0x00) {
3798                                                                                                 synclyrics_info = (AvSynclyricsInfo *)mmfile_malloc(sizeof(AvSynclyricsInfo));
3799                                                                                                 if (synclyrics_info) {
3800                                                                                                         if (textEncodingType == AV_ID3V2_UTF8) {
3801                                                                                                                 synclyrics_info->lyric_info = mmfile_malloc(copy_len + 1);
3802                                                                                                                 if (synclyrics_info->lyric_info) {
3803                                                                                                                         memset(synclyrics_info->lyric_info, 0, copy_len + 1);
3804                                                                                                                         memcpy(synclyrics_info->lyric_info, pExtContent + copy_start_pos, copy_len);
3805                                                                                                                         synclyrics_info->lyric_info[copy_len] = '\0';
3806                                                                                                                 }
3807                                                                                                         } else {
3808                                                                                                                 synclyrics_info->lyric_info = mmfile_string_convert((const char *)&pExtContent[copy_start_pos], copy_len, "UTF-8", charset_array[textEncodingType], NULL, NULL);
3809                                                                                                         }
3810
3811                                                                                                         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];
3812                                                                                                         idx += 4;
3813                                                                                                         copy_start_pos = tmp + idx + 1;
3814                                                                                                         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);
3815                                                                                                         copy_len = 0;
3816                                                                                                         synclyrics_info_list = g_list_append(synclyrics_info_list, synclyrics_info);
3817                                                                                                 }
3818                                                                                         }
3819                                                                                         copy_len++;
3820                                                                                 }
3821                                                                                 pInfo->pSyncLyrics = synclyrics_info_list;
3822                                                                                 pInfo->syncLyricsNum = g_list_length(pInfo->pSyncLyrics);
3823                                                                         }
3824                                                                 }
3825                                                         } else {
3826                                                                 debug_msg(RELEASE, "SyncLyrics info too small to parse realCpyFrameNum(%d)\n", realCpyFrameNum);
3827                                                         }
3828
3829                                                         tmp = 0;
3830                                                         pInfo->tagV2Info.bSyncLyricsMarked = true;
3831                                                 } else if (strncmp((char *)CompTmp, "USLT", 4) == 0 && pInfo->tagV2Info.bUnsyncLyricsMarked == false) {
3832                                                         if (realCpyFrameNum > 3) {
3833                                                                 realCpyFrameNum -= 3;
3834                                                                 tmp = 3;
3835
3836                                                                 if (textEncodingType == AV_ID3V2_UTF16 || textEncodingType == AV_ID3V2_UTF16_BE) {
3837                                                                         while ((NEWLINE_OF_UTF16(pExtContent + tmp) || NEWLINE_OF_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 4) {
3838                                                                                 realCpyFrameNum -= 4;
3839                                                                                 tmp += 4;
3840                                                                         }
3841
3842                                                                         if ((IS_ENCODEDBY_UTF16(pExtContent + tmp) || IS_ENCODEDBY_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 2) {
3843                                                                                 realCpyFrameNum -= 2;
3844                                                                                 tmp += 2;
3845                                                                                 textEncodingType = AV_ID3V2_UTF16;
3846                                                                         } else {
3847                                                                                 debug_msg(RELEASE, "pInfo->pUnsyncLyrics Never Get Here!!\n");
3848                                                                         }
3849                                                                 } else if (textEncodingType == AV_ID3V2_UTF8) {
3850                                                                         while (pExtContent[tmp] < 0x20 && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
3851                                                                                 realCpyFrameNum--;
3852                                                                                 tmp++;
3853                                                                         }
3854                                                                         textEncodingType = AV_ID3V2_UTF8;
3855                                                                 } else {
3856                                                                         while (pExtContent[tmp] < 0x20 && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
3857                                                                                 realCpyFrameNum--;
3858                                                                                 tmp++;
3859                                                                         }
3860                                                                         textEncodingType = AV_ID3V2_ISO_8859;
3861                                                                 }
3862
3863                                                                 debug_msg(RELEASE, "tmp(%d) textEncodingType(%d), realCpyFrameNum(%d)\n", tmp, textEncodingType, realCpyFrameNum);
3864
3865                                                                 pInfo->pUnsyncLyrics = _mm_file_string_convert_v224((const char *)&pExtContent[tmp], realCpyFrameNum, textEncodingType, charset_array[textEncodingType], &pInfo->unsynclyricsLen);
3866                                                         } else {
3867                                                                 debug_msg(RELEASE, "Description info too small to parse realCpyFrameNum(%d)\n", realCpyFrameNum);
3868                                                         }
3869
3870                                                         tmp = 0;
3871
3872                                                         debug_msg(RELEASE, "pInfo->pUnsyncLyrics returned = (%s), pInfo->unsynclyricsLen(%d)\n", pInfo->pUnsyncLyrics, pInfo->unsynclyricsLen);
3873                                                         pInfo->tagV2Info.bDescriptionMarked = true;
3874                                                 } else if (strncmp((char *)CompTmp, "TCON", 4) == 0 && pInfo->tagV2Info.bGenreMarked == false) {
3875                                                         pInfo->pGenre = _mm_file_string_convert_v224((const char *)pExtContent, realCpyFrameNum, textEncodingType, charset_array[textEncodingType], &pInfo->genreLen);
3876                                                         debug_msg(RELEASE, "pInfo->pGenre returned = (%s), pInfo->genreLen(%d)\n", pInfo->pGenre, pInfo->genreLen);
3877                                                         _mm_file_id3tag_add_bracket_at_genre(&pInfo->pGenre, pInfo->genreLen);
3878                                                         pInfo->tagV2Info.bGenreMarked = true;
3879                                                 } else if (strncmp((char *)CompTmp, "TRCK", 4) == 0 && pInfo->tagV2Info.bTrackNumMarked == false) {
3880                                                         pInfo->pTrackNum = _mm_file_string_convert_v224((const char *)pExtContent, realCpyFrameNum, textEncodingType, charset_array[textEncodingType], &pInfo->tracknumLen);
3881                                                         debug_msg(RELEASE, "pInfo->pTrackNum returned = (%s), pInfo->tracknumLen(%d)\n", pInfo->pTrackNum, pInfo->tracknumLen);
3882                                                         pInfo->tagV2Info.bTrackNumMarked = true;
3883                                                 } else if (strncmp((char *)CompTmp, "TPOS", 4) == 0 && pInfo->tagV2Info.bPartOfASetMarked == false) {
3884                                                         pInfo->pPartOfASet = _mm_file_string_convert_v224((const char *)pExtContent, realCpyFrameNum, textEncodingType, charset_array[textEncodingType], &pInfo->partofsetLen);
3885                                                         debug_msg(RELEASE,  "pInfo->pPartOfASet returned = (%s), pInfo->partofsetLen(%d)\n", pInfo->pPartOfASet, pInfo->partofsetLen);
3886                                                         pInfo->tagV2Info.bPartOfASetMarked = true;
3887                                                 } else if (strncmp((char *)CompTmp, "TENC", 4) == 0 && pInfo->tagV2Info.bEncByMarked == false) {
3888                                                         pInfo->pEncBy = _mm_file_string_convert_v224((const char *)pExtContent, realCpyFrameNum, textEncodingType, charset_array[textEncodingType], &pInfo->encbyLen);
3889                                                         debug_msg(RELEASE, "pInfo->pEncBy returned = (%s), pInfo->encbyLen(%d)\n", pInfo->pEncBy, pInfo->encbyLen);
3890                                                         pInfo->tagV2Info.bEncByMarked = true;
3891                                                 } else if (strncmp((char *)CompTmp, "WXXX", 4) == 0 && pInfo->tagV2Info.bURLMarked == false) {
3892                                                         pInfo->pURL = _mm_file_string_convert_v224((const char *)pExtContent, realCpyFrameNum, textEncodingType, charset_array[textEncodingType], &pInfo->urlLen);
3893                                                         debug_msg(RELEASE, "pInfo->pURL returned = (%s), pInfo->urlLen(%d)\n", pInfo->pURL, pInfo->urlLen);
3894                                                         pInfo->tagV2Info.bURLMarked = true;
3895                                                 } else if (strncmp((char *)CompTmp, "TCOP", 4) == 0 && pInfo->tagV2Info.bCopyRightMarked == false) {
3896                                                         pInfo->pCopyright = _mm_file_string_convert_v224((const char *)pExtContent, realCpyFrameNum, textEncodingType, charset_array[textEncodingType], &pInfo->copyrightLen);
3897                                                         debug_msg(RELEASE, "pInfo->pCopyright returned = (%s), pInfo->copyrightLen(%d)\n", pInfo->pCopyright, pInfo->copyrightLen);
3898                                                         pInfo->tagV2Info.bCopyRightMarked = true;
3899                                                 } else if (strncmp((char *)CompTmp, "TOPE", 4) == 0 && pInfo->tagV2Info.bOriginArtistMarked == false) {
3900                                                         pInfo->pOriginArtist = _mm_file_string_convert_v224((const char *)pExtContent, realCpyFrameNum, textEncodingType, charset_array[textEncodingType], &pInfo->originartistLen);
3901                                                         debug_msg(RELEASE, "pInfo->pOriginArtist returned = (%s), pInfo->originartistLen(%d)\n", pInfo->pOriginArtist, pInfo->originartistLen);
3902                                                         pInfo->tagV2Info.bOriginArtistMarked = true;
3903                                                 } else if (strncmp((char *)CompTmp, "TCOM", 4) == 0 && pInfo->tagV2Info.bComposerMarked == false) {
3904                                                         pInfo->pComposer = _mm_file_string_convert_v224((const char *)pExtContent, realCpyFrameNum, textEncodingType, charset_array[textEncodingType], &pInfo->composerLen);
3905                                                         debug_msg(RELEASE, "pInfo->pComposer returned = (%s), pInfo->originartistLen(%d)\n", pInfo->pComposer, pInfo->composerLen);
3906                                                         pInfo->tagV2Info.bComposerMarked = true;
3907                                                 } else if (strncmp((char *)CompTmp, "TDRC", 4) == 0 && pInfo->tagV2Info.bRecDateMarked == false) {      /*TYER(year) and TRDA are replaced by the TDRC */
3908                                                         pInfo->pRecDate = _mm_file_string_convert_v224((const char *)pExtContent, realCpyFrameNum, textEncodingType, charset_array[textEncodingType], &pInfo->recdateLen);
3909                                                         debug_msg(RELEASE, "pInfo->pRecDate returned = (%s), pInfo->recdateLen(%d)\n", pInfo->pRecDate, pInfo->recdateLen);
3910                                                         pInfo->tagV2Info.bRecDateMarked = true;
3911                                                 } else if (strncmp((char *)CompTmp, "TIT1", 4) == 0 && pInfo->tagV2Info.bContentGroupMarked == false) {
3912                                                         pInfo->pContentGroup = _mm_file_string_convert_v224((const char *)pExtContent, realCpyFrameNum, textEncodingType, charset_array[textEncodingType], &pInfo->contentGroupLen);
3913                                                         debug_msg(RELEASE, "pInfo->pContentGroup returned = (%s), pInfo->contentGroupLen(%d)\n", pInfo->pContentGroup, pInfo->contentGroupLen);
3914                                                         pInfo->tagV2Info.bContentGroupMarked = true;
3915                                                 } else if (strncmp((char *)CompTmp, "APIC", 4) == 0 && pInfo->tagV2Info.bImageMarked == false && realCpyFrameNum <= 2000000) {
3916                                                         debug_msg(DEBUG, "text encoding %d \n", textEncodingType);
3917                                                         if (!_mm_file_id3tag_parse_APIC(pInfo, pExtContent, realCpyFrameNum, (const char*)charset_array[textEncodingType]))
3918                                                                 continue;
3919                                                         pInfo->tagV2Info.bImageMarked = true;
3920                                                 } else {
3921                                                         debug_msg(RELEASE, "CompTmp(%s) This Frame ID currently not Supports!!\n", CompTmp);
3922                                                 }
3923                                         }
3924
3925                                 } else {
3926                                         debug_msg(RELEASE, "mmf_file_id3tag_parse_v224: All of the pExtContent Values are NULL\n");
3927                                 }
3928
3929                         } else {
3930                                 curPos += purelyFramelen;
3931                                 if (purelyFramelen != 0)
3932                                         needToloopv2taglen = MP3_TAGv2_23_TXT_HEADER_LEN;
3933                         }
3934
3935                         mmfile_free(pExtContent);
3936                         memset(CompTmp, 0, 4);
3937                         if (curPos < taglen) {
3938                                 needToloopv2taglen -= oneFrameLen;
3939                                 v2numOfFrames++;
3940                         } else
3941                                 needToloopv2taglen = MP3_TAGv2_23_TXT_HEADER_LEN;
3942
3943                         oneFrameLen = 0;
3944                         encodingOffSet = 0;
3945                         realCpyFrameNum = 0;
3946                         textEncodingType = 0;
3947                         purelyFramelen = 0;
3948
3949                 }
3950         }
3951
3952         release_characterset_array(charset_array);
3953
3954         if (taglen)
3955                 return true;
3956         else
3957                 return false;
3958
3959 }
3960
3961 EXPORT_API
3962 void mm_file_id3tag_restore_content_info(AvFileContentInfo *pInfo)
3963 {
3964         char    *mpegAudioGenre = NULL/*, *tmpGenreForV1Tag = NULL*/;
3965         bool    bAdditionGenre = false /*, bMpegAudioFrame = false*/;
3966         int mpegAudioFileLen = 0, idv2IntGenre = 148/*, tmpinx = 0, tmpinx2=0*/;
3967         unsigned char genre = pInfo->genre;
3968
3969         /* for Genre Info */
3970         if (pInfo->tagV2Info.bGenreMarked == false) {
3971                 if (pInfo->bV1tagFound == true) {
3972                         debug_msg(RELEASE, "Genre: %d\n", genre);
3973
3974                         if (genre > 147)
3975                                 genre = 148;
3976
3977                         if (MpegAudio_Genre[genre] != NULL) {
3978                                 pInfo->genreLen = strlen(MpegAudio_Genre[genre]);
3979                                 if (pInfo->genreLen > 0) {
3980                                         /* Give space for NULL character. Hence added "+1" */
3981                                         pInfo->pGenre = mmfile_malloc(sizeof(char) * (pInfo->genreLen + 1));
3982                                         if (pInfo->pGenre) {
3983                                                 SAFE_STRLCPY(pInfo->pGenre, MpegAudio_Genre[genre], pInfo->genreLen + 1);
3984                                         }
3985                                 }
3986                         }
3987                 } else {
3988                         debug_msg(RELEASE, "Genre was not Found.\n");
3989                 }
3990         } else if (pInfo->tagV2Info.bGenreMarked == true) {
3991                 if (pInfo->genreLen && pInfo->tagV2Info.bGenreUTF16) {
3992                         pInfo->pGenre[pInfo->genreLen + 1] = '\0';
3993                         mpegAudioGenre = mmfile_malloc(sizeof(char) * (pInfo->genreLen * AV_WM_LOCALCODE_SIZE_MAX + 1));
3994                 } else {
3995                         debug_msg(RELEASE, "pInfo->genreLen size is Zero Or not UTF16 code! genreLen[%d] genre[%s]\n", pInfo->genreLen, pInfo->pGenre);
3996
3997                         if (pInfo->pGenre) {
3998                                 pInfo->genreLen = strlen(pInfo->pGenre);
3999                                 mpegAudioGenre = mmfile_malloc(sizeof(char) * (pInfo->genreLen + 1));
4000                                 if (mpegAudioGenre != NULL) {
4001                                         SAFE_STRLCPY(mpegAudioGenre, pInfo->pGenre, pInfo->genreLen + 1);
4002                                 }
4003                         } else {
4004                                 pInfo->genreLen = 0;
4005                         }
4006                 }
4007
4008                 mmfile_free(pInfo->pGenre);
4009
4010                 /*tmpinx = 0;*/
4011                 if (mpegAudioGenre != NULL) {
4012                         /**
4013                          *Genre number
4014                          * (XXX)        XXX is 0 - 148
4015                          */
4016                         pInfo->genreLen = strlen(mpegAudioGenre);
4017                         if (pInfo->genreLen >= 3 &&
4018                             mpegAudioGenre[0] == '(' && mpegAudioGenre[pInfo->genreLen - 1] == ')') {
4019                                 bAdditionGenre = true;
4020                                 for (mpegAudioFileLen = 1; mpegAudioFileLen <= pInfo->genreLen - 2; mpegAudioFileLen++) {
4021                                         if (mpegAudioGenre[mpegAudioFileLen] < '0' || mpegAudioGenre[mpegAudioFileLen] > '9') {
4022                                                 bAdditionGenre = false;
4023                                                 break;
4024                                         }
4025                                 }
4026                         }
4027
4028                         if (bAdditionGenre == true) {
4029                                 idv2IntGenre = atoi(mpegAudioGenre + 1);
4030
4031                                 if (idv2IntGenre > 147 || idv2IntGenre < 0)
4032                                         idv2IntGenre = 148;
4033
4034                                 if (MpegAudio_Genre[idv2IntGenre] != NULL) {
4035                                         pInfo->genreLen = strlen(MpegAudio_Genre[idv2IntGenre]);
4036                                         if (pInfo->genreLen > 0) {
4037                                                 /* Give space for NULL character. Hence added "+1" */
4038                                                 pInfo->pGenre = mmfile_malloc(sizeof(char) * (pInfo->genreLen + 1));
4039                                                 if (pInfo->pGenre) {
4040                                                         SAFE_STRLCPY(pInfo->pGenre, MpegAudio_Genre[idv2IntGenre], pInfo->genreLen + 1);
4041                                                 }
4042                                         }
4043                                 }
4044                                 debug_msg(RELEASE, "pInfo->pGenre = %s\n", pInfo->pGenre);
4045                         } else if (bAdditionGenre == false && pInfo->genreLen > 0) {
4046                                 /**
4047                                  * Genre string.
4048                                  */
4049
4050                                 /* Give space for NULL character. Hence added "+1" */
4051                                 pInfo->pGenre = mmfile_malloc(sizeof(char) * (pInfo->genreLen + 1));
4052                                 if (pInfo->pGenre) {
4053                                         SAFE_STRLCPY(pInfo->pGenre, mpegAudioGenre, pInfo->genreLen + 1);
4054                                 }
4055                                 debug_msg(RELEASE, "pInfo->pGenre = %s, pInfo->genreLen = %d\n", pInfo->pGenre, pInfo->genreLen);
4056                         } else {
4057                                 debug_msg(RELEASE, "Failed to \"(...)\" value to genre = %s\n", pInfo->pGenre);
4058                         }
4059                 } else {
4060                         debug_msg(RELEASE, "mpegAudioGenre = %s\n", mpegAudioGenre);
4061                 }
4062                 mmfile_free(mpegAudioGenre);
4063
4064         } else {
4065                 debug_msg(RELEASE, "Neither ID3 v1 nor v2 info doesn't have Genre Info.\n");
4066         }
4067
4068 }
4069
4070 void mm_file_free_synclyrics_list(GList *synclyrics_list)
4071 {
4072         int list_len = 0;
4073         int idx = 0;
4074         AvSynclyricsInfo *synclyrics_info = NULL;
4075
4076         if (synclyrics_list == NULL) {
4077                 return;
4078         }
4079
4080         list_len = g_list_length(synclyrics_list);
4081         for (idx = 0; idx < list_len; idx++) {
4082                 synclyrics_info = g_list_nth_data(synclyrics_list, idx);
4083
4084                 if (synclyrics_info != NULL) {
4085                         mmfile_free(synclyrics_info->lyric_info);
4086                         mmfile_free(synclyrics_info);
4087                 }
4088         }
4089
4090         if (synclyrics_list != NULL) {
4091                 g_list_free(synclyrics_list);
4092                 synclyrics_list = NULL;
4093         }
4094
4095         return;
4096 }
4097