[RQ170606-00002] fix invalid format argument types for dlog
[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
30 #include "mm_file.h"
31 #include "mm_file_debug.h"
32 #include "mm_file_utils.h"
33
34 #define ENABLE_ITUNES_META              /*All itunes metadata extracted by ffmpeg. see mov_read_udta_string() but Some cover art not support. */
35
36 typedef struct _mmfilemp4basicboxheader {
37         unsigned int size;
38         unsigned int type;
39         long long start_offset; /*huge file*/
40 } MMFILE_MP4_BASIC_BOX_HEADER;
41
42 typedef struct _mmfilemp4ftpybox {
43         unsigned int major_brand;
44         unsigned short major_version;
45         unsigned short minor_version;
46         unsigned int *compatiable_brands;
47 } MMFILE_MP4_FTYPBOX;
48
49 typedef enum {
50         eMMFILE_3GP_TAG_TITLE = 0x01,
51         eMMFILE_3GP_TAG_CAPTION = 0x02,
52         eMMFILE_3GP_TAG_COPYRIGHT = 0x03,
53         eMMFILE_3GP_TAG_PERFORMER = 0x04,
54         eMMFILE_3GP_TAG_AUTHOR = 0x05,
55         eMMFILE_3GP_TAG_GENRE = 0x06,
56 } eMMFILE_3GP_TEXT_TAG;
57
58 typedef struct _mmfile3gptagtextbox {
59         unsigned char version;
60         unsigned char flag[3];
61         unsigned char language[2];
62         unsigned char *text;
63 } MMFILE_3GP_TEXT_TAGBOX;
64
65 typedef struct _mmfile3gptagyearbox {
66         unsigned char version;
67         unsigned char flag[3];
68         unsigned short year;
69 } MMFILE_3GP_YEAR_TAGBOX;
70
71 typedef struct _mmfile3gptagalbumbox {
72         unsigned char version;
73         unsigned char flag[3];
74         unsigned char language[2];
75         unsigned char *albumtile;
76         unsigned char trackNumber;
77 } MMFILE_3GP_ALBUM_TAGBOX;
78
79 typedef struct _mmfile3gpratingbox {
80         unsigned char version;
81         unsigned char flag[3];
82         unsigned int  ratingEntity;
83         unsigned int  ratingCriteria;
84         unsigned char language[2];
85         unsigned char *ratingInfo;
86 } MMFILE_3GP_RATING_TAGBOX;
87
88 typedef struct _mmfile3gpclsfbox {
89         unsigned char version;
90         unsigned char flag[3];
91         unsigned int  classificationEntity;
92         unsigned int  classificationTable;
93         unsigned char language[2];
94         unsigned char *classificationInfo;
95 } MMFILE_3GP_CLASSIFICATION_TAGBOX;
96
97 typedef struct _mmfile3gphdlrbox {
98         unsigned int  version;
99         unsigned int  pre_defined;
100         unsigned int  handler_type;
101         unsigned int  reserved[3];
102         unsigned char *boxname;
103 } MMFILE_3GP_HANDLER_BOX;
104
105 typedef struct _mmfileidv2box {
106         unsigned char version;
107         unsigned char flag[3];
108         unsigned char language[2];
109         unsigned char *id3v2Data;
110 } MMFILE_3GP_ID3V2_BOX;
111
112 typedef struct _mmfilelocibox {
113         unsigned char version;
114         unsigned char flag[3];
115         unsigned char language[2];
116         unsigned char *name;
117         unsigned char role;
118         float         longitude;
119         float         latitude;
120         float         altitude;
121         unsigned char *astronomical_body;
122         unsigned char *additional_notes;
123 } MMFILE_3GP_LOCATION_TAGBOX;
124
125 typedef struct _mmfilesmtabox {
126         unsigned int tmp;
127         unsigned int length;
128         unsigned char saut[4];
129         unsigned int value;
130 } MMFILE_M4A_SMTA_TAGBOX;
131
132 #define MMFILE_MP4_BASIC_BOX_HEADER_LEN 8
133 #define MMFILE_MP4_MOVIE_HEADER_BOX_LEN 96
134 #define MMFILE_MP4_HDLR_BOX_LEN         24
135 #define MMFILE_MP4_STSZ_BOX_LEN         20
136 #define MMFILE_MP4_MP4VBOX_LEN          80
137 #define MMFILE_MP4_MP4ABOX_LEN          28
138 #define MMFILE_3GP_TEXT_TAGBOX_LEN      6
139 #define MMFILE_3GP_YEAR_TAGBOX_LEN      6
140 #define MMFILE_3GP_ALBUM_TAGBOX_LEN     6
141 #define MMFILE_3GP_RATING_TAGBOX_LEN    14
142 #define MMFILE_3GP_CLASS_TAGBOX_LEN     14
143 #define MMFILE_3GP_HANDLER_BOX_LEN      24
144 #define MMFILE_3GP_ID3V2_BOX_LEN        6
145 #define MMFILE_SYNC_LYRIC_INFO_MIN_LEN        5
146
147
148 #define FOURCC(a, b, c, d) ((a) + ((b) << 8) + ((c) << 16) + ((d) << 24))
149
150 /*#define       MIN(a, b) (((a) < (b)) ? (a):(b))*/
151
152 #define GENRE_COUNT     149
153
154 static const char *MpegAudio_Genre[GENRE_COUNT] = {"Blues", "Classic Rock", "Country", "Dance", "Disco", "Funk", "Grunge", "Hip-Hop", "Jazz", "Metal",
155                                                                                                 "New Age", "Oldies", "Other", "Pop", "R&B", "Rap", "Reggae", "Rock", "Techno", "Industrial",
156                                                                                                 "Alternative", "Ska", "Death Metal", "Pranks", "Soundtrack", "Euro-Techno", "Ambient", "Trip-Hop", "Vocal", "Jazz+Funk",
157                                                                                                 "Fusion", "Trance", "Classical", "Instrumental", "Acid", "House", "Game", "Sound Clip", "Gospel", "Noise",
158                                                                                                 "AlternRock", "Bass", "Soul", "Punk", "Space", "Meditative", "Instrumental Pop", "Instrumental Rock", "Ethnic", "Gothic",
159                                                                                                 "Darkwave", "Techno-Industrial", "Electronic", "Pop-Folk", "Eurodance", "Dream", "Southern Rock", "Comedy", "Cult", "Gangsta",
160                                                                                                 "Top 40", "Christian Rap", "Pop/Funk", "Jungle", "Native American", "Cabaret", "New Wave", "Psychadelic", "Rave", "Showtunes",
161                                                                                                 "Trailer", "Lo-Fi", "Tribal", "Acid Punk", "Acid Jazz", "Polka", "Retro", "Musical", "Rock & Roll", "Hard Rock",
162                                                                                                 "Folk", "Folk-Rock", "National Folk", "Swing", "Fast Fusion", "Bebob", "Latin", "Revival", "Celtic", "Bluegrass",
163                                                                                                 "Avantgarde", "Gothic Rock", "Progressive Rock", "Psychedelic Rock", "Symphonic Rock", "Slow Rock", "Big Band", "Chorus", "Easy Listening", "Acoustic",
164                                                                                                 "Humour", "Speech", "Chanson", "Opera", "Chamber Music", "Sonata", "Symphony", "Booty Bass", "Primus", "Porn Groove",
165                                                                                                 "Satire", "Slow Jam", "Club", "Tango", "Samba", "Folklore", "Ballad", "Power Ballad", "Rhythmic Soul", "Freestyle",
166                                                                                                 "Duet", "Punk Rock", "Drum Solo", "A capella", "Euro-House", "Dance Hall", "Goa", "Drum & Bass", "Club-House", "Hardcore",
167                                                                                                 "Terror", "Indie", "BritPop", "Negerpunk", "Polsk Punk", "Beat", "Christian", "Heavy Metal", "Black Metal", "Crossover",
168                                                                                                 "Contemporary", "Christian Rock", "Merengue", "Salsa", "Thrash Metal", "Anime", "JPop", "Synthpop", "Unknown"
169                                                                                                 };
170
171 static unsigned char gTagJPEGHeader[] = {0xff, 0xd8, 0xff };
172 static unsigned char gTagPNGHeader[] = {0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a };
173
174 static int GetJunkCounterLimit(void);
175
176 static int GetStringFromTextTagBox(MMFileFormatContext *formatContext, MMFileIOHandle *fp, MMFILE_MP4_BASIC_BOX_HEADER *basic_header, eMMFILE_3GP_TEXT_TAG eTag)
177 {
178         int ret = MMFILE_UTIL_FAIL;    /*fail*/
179         MMFILE_3GP_TEXT_TAGBOX texttag = {0, };
180         int readed = 0;
181         int textBytes = 0;
182         char *temp_text = NULL;
183
184         if (!formatContext || !fp || !basic_header) {
185                 debug_error(DEBUG, "invalid param\n");
186                 return MMFILE_UTIL_FAIL;
187         }
188
189         textBytes = basic_header->size - MMFILE_MP4_BASIC_BOX_HEADER_LEN - MMFILE_3GP_TEXT_TAGBOX_LEN;
190
191         readed = mmfile_read(fp, (unsigned char *)&texttag, MMFILE_3GP_TEXT_TAGBOX_LEN);
192         if (readed != MMFILE_3GP_TEXT_TAGBOX_LEN) {
193                 debug_error(DEBUG, "read text tag header fail\n");
194                 ret = MMFILE_UTIL_FAIL;
195                 goto exception;
196         }
197
198         if (textBytes <= 1) { /* there exist only 00(null) */
199                 debug_error(DEBUG, "Text is NULL\n");
200                 goto exception;
201         }
202
203         texttag.text = mmfile_malloc(textBytes);
204         if (!texttag.text) {
205                 debug_error(DEBUG, "malloc fail for text box\n");
206                 ret = MMFILE_UTIL_FAIL;
207                 goto exception;
208         }
209
210         readed = mmfile_read(fp, (unsigned char *)texttag.text, textBytes);
211         if (readed != textBytes) {
212                 debug_error(DEBUG, "read text fail\n");
213                 ret = MMFILE_UTIL_FAIL;
214                 goto exception;
215         }
216
217         /* check BOM char */
218         if ((texttag.text[0] == 0xFE) && (texttag.text[1] == 0xFF)) {
219                 /* this char is UTF-16 */
220                 unsigned int bytes_written = 0;
221                 temp_text = mmfile_string_convert((const char *)&texttag.text[2], readed - 2, "UTF-8", "UTF-16", NULL, (unsigned int *)&bytes_written);
222         } else {
223                 temp_text = mmfile_strdup((const char *)texttag.text);
224         }
225
226         switch (eTag) {
227                 case eMMFILE_3GP_TAG_TITLE: {
228                                 if (!formatContext->title) {
229                                         formatContext->title = temp_text;
230                                 }
231                                 break;
232                         }
233                 case eMMFILE_3GP_TAG_CAPTION: {
234                                 if (!formatContext->description) {
235                                         formatContext->description = temp_text;
236                                 }
237                                 break;
238                         }
239                 case eMMFILE_3GP_TAG_COPYRIGHT: {
240                                 if (!formatContext->copyright) {
241                                         formatContext->copyright = temp_text;
242                                 }
243                                 break;
244                         }
245                 case eMMFILE_3GP_TAG_PERFORMER: {
246                                 if (!formatContext->artist) {
247                                         formatContext->artist = temp_text;
248                                 }
249                                 break;
250                         }
251                 case eMMFILE_3GP_TAG_AUTHOR: {
252                                 if (!formatContext->author) {
253                                         formatContext->author = temp_text;
254                                 }
255                                 break;
256                         }
257                 case eMMFILE_3GP_TAG_GENRE: {
258                                 if (!formatContext->genre) {
259                                         formatContext->genre = temp_text;
260                                 }
261                                 break;
262                         }
263                 default: {
264                                 debug_warning(DEBUG, "Not supported Text Tag type[%d]\n", eTag);
265                                 break;
266                         }
267         }
268
269         mmfile_free(texttag.text);
270         texttag.text = NULL;
271         mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
272
273         return MMFILE_UTIL_SUCCESS;
274
275 exception:
276         mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
277         if (texttag.text) {
278                 mmfile_free(texttag.text);
279         }
280         return ret;
281 }
282
283 static int GetYearFromYearTagBox(MMFileFormatContext *formatContext, MMFileIOHandle *fp, MMFILE_MP4_BASIC_BOX_HEADER *basic_header)
284 {
285 #define MAX_YEAR_BUFFER 10
286         int readed = 0;
287         MMFILE_3GP_YEAR_TAGBOX yearbox = {0, };
288         char temp_year[MAX_YEAR_BUFFER] = {0, };
289
290         if (!formatContext || !fp || !basic_header) {
291                 debug_error(DEBUG, "invalid param\n");
292                 return MMFILE_UTIL_FAIL;
293         }
294
295         readed = mmfile_read(fp, (unsigned char *)&yearbox, MMFILE_3GP_YEAR_TAGBOX_LEN);
296         if (readed != MMFILE_3GP_YEAR_TAGBOX_LEN) {
297                 debug_error(DEBUG, "read yeartag header fail\n");
298                 goto exception;
299         }
300
301         if (!formatContext->year) {
302                 yearbox.year = mmfile_io_be_int16(yearbox.year);
303                 snprintf(temp_year, MAX_YEAR_BUFFER, "%d", yearbox.year);
304                 temp_year[MAX_YEAR_BUFFER - 1] = '\0';
305                 formatContext->year = mmfile_strdup((const char *)temp_year);
306         }
307
308         mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
309         return MMFILE_UTIL_SUCCESS;
310
311 exception:
312         mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
313
314         return MMFILE_UTIL_FAIL;
315 }
316
317 static int GetAlbumFromAlbumTagBox(MMFileFormatContext *formatContext, MMFileIOHandle *fp, MMFILE_MP4_BASIC_BOX_HEADER *basic_header)
318 {
319         int albumTitleLen = 0;
320         char *temp_text = NULL;
321         int readed = 0;
322         int trackFlags = 0;
323         MMFILE_3GP_ALBUM_TAGBOX albumbox = {0, };
324
325         if (!formatContext || !fp || !basic_header) {
326                 debug_error(DEBUG, "invalid param\n");
327                 return MMFILE_UTIL_FAIL;
328         }
329
330         readed = mmfile_read(fp, (unsigned char *)&albumbox, MMFILE_3GP_ALBUM_TAGBOX_LEN);
331         if (readed != MMFILE_3GP_ALBUM_TAGBOX_LEN) {
332                 debug_error(DEBUG, "read albumtag header fail\n");
333                 goto exception;
334         }
335
336         albumTitleLen = basic_header->size - MMFILE_MP4_BASIC_BOX_HEADER_LEN - MMFILE_3GP_ALBUM_TAGBOX_LEN - 1; /* 1: track number */
337         if (albumTitleLen > 1) { /* there exist only 00(null) */
338                 debug_msg(RELEASE, "albumTitleLen=%d\n", albumTitleLen);
339
340                 albumbox.albumtile = mmfile_malloc(albumTitleLen + 1);  /* 1: for null char */
341                 if (!albumbox.albumtile) {
342                         debug_error(DEBUG, "malloc fail for album title text\n");
343                         goto exception;
344                 }
345
346                 readed = mmfile_read(fp, (unsigned char *)albumbox.albumtile, albumTitleLen);
347                 if (readed != albumTitleLen) {
348                         debug_error(DEBUG, "read album title fail\n");
349                         goto exception;
350                 }
351
352                 if (albumbox.albumtile[albumTitleLen - 1] == '\0') { /* there exist track number */
353                         trackFlags = 1;
354                 } else {
355                         trackFlags = 0;
356                         readed = mmfile_read(fp, (unsigned char *)&(albumbox.albumtile[albumTitleLen]), 1);
357                         if (readed != 1) {
358                                 debug_error(DEBUG, "read album title fail\n");
359                                 goto exception;
360                         }
361                         albumbox.albumtile[albumTitleLen] = '\0';
362                 }
363
364                 /* check BOM char */
365                 if ((albumbox.albumtile[0] == 0xFE) && (albumbox.albumtile[1] == 0xFF)) {
366                         /* this char is UTF-16 */
367                         unsigned int bytes_written = 0;
368                         temp_text = mmfile_string_convert((const char *)&albumbox.albumtile[2], readed - 2, "UTF-8", "UTF-16", NULL, (unsigned int *)&bytes_written);
369                 } else {
370                         temp_text = mmfile_strdup((const char *)albumbox.albumtile);
371                 }
372
373                 if (!formatContext->album) {
374                         formatContext->album = temp_text;
375                 }
376
377                 debug_msg(RELEASE, "formatContext->album=%s, strlen=%d\n", formatContext->album, strlen(formatContext->album));
378         }
379
380         if (trackFlags) {
381                 readed = mmfile_read(fp, (unsigned char *)&albumbox.trackNumber, 1);
382                 if (readed != 1) {
383                         debug_error(DEBUG, "read track number fail\n");
384                         goto exception;
385                 }
386
387                 if (formatContext->tagTrackNum == 0) {
388                         char tracknum[10] = {0, };
389                         snprintf(tracknum, 10, "%d", albumbox.trackNumber);
390                         tracknum[9] = '\0';
391                         formatContext->tagTrackNum = mmfile_strdup((const char *)tracknum);
392                 }
393         }
394
395         mmfile_free(albumbox.albumtile);
396         mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
397
398         return MMFILE_UTIL_SUCCESS;
399
400 exception:
401         mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
402         mmfile_free(albumbox.albumtile);
403
404         return MMFILE_UTIL_FAIL;
405 }
406
407 static int GetRatingFromRatingTagBox(MMFileFormatContext *formatContext, MMFileIOHandle *fp, MMFILE_MP4_BASIC_BOX_HEADER *basic_header)
408 {
409         int readed = 0;
410         int  ratinginfoLen = 0;
411         char *temp_text = NULL;
412
413         MMFILE_3GP_RATING_TAGBOX ratingTag = {0, };
414
415         if (!formatContext || !fp || !basic_header) {
416                 debug_error(DEBUG, "invalid param\n");
417                 return MMFILE_UTIL_FAIL;
418         }
419
420         readed = mmfile_read(fp, (unsigned char *)&ratingTag, MMFILE_3GP_RATING_TAGBOX_LEN);
421         if (readed != MMFILE_3GP_RATING_TAGBOX_LEN) {
422                 debug_error(DEBUG, "read rating tag header fail\n");
423                 goto exception;
424         }
425
426         ratinginfoLen = basic_header->size - MMFILE_MP4_BASIC_BOX_HEADER_LEN - MMFILE_3GP_RATING_TAGBOX_LEN;
427
428         if (ratinginfoLen == 1) {
429                 debug_error(DEBUG, "Rating Text is NULL\n");
430                 goto exception;
431         }
432
433         ratingTag.ratingInfo = mmfile_malloc(ratinginfoLen);
434         if (!ratingTag.ratingInfo) {
435                 debug_error(DEBUG, "rating info error\n");
436                 goto exception;
437         }
438
439         readed = mmfile_read(fp, (unsigned char *)ratingTag.ratingInfo, ratinginfoLen);
440         if (readed != ratinginfoLen) {
441                 debug_error(DEBUG, "read rating info string fail\n");
442                 goto exception;
443         }
444
445         /* check BOM char */
446         if ((ratingTag.ratingInfo[0] == 0xFE) && (ratingTag.ratingInfo[1] == 0xFF)) {
447                 /* this char is UTF-16 */
448                 unsigned int bytes_written = 0;
449                 temp_text = mmfile_string_convert((const char *)&ratingTag.ratingInfo[2], readed - 2, "UTF-8", "UTF-16", NULL, (unsigned int *)&bytes_written);
450         } else {
451                 temp_text = mmfile_strdup((const char *)ratingTag.ratingInfo);
452         }
453
454         if (!formatContext->rating) {
455                 formatContext->rating = temp_text;
456         } else {
457                 mmfile_free(temp_text);
458         }
459
460         mmfile_free(ratingTag.ratingInfo);
461         mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
462
463         return MMFILE_UTIL_SUCCESS;
464
465 exception:
466         mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
467         mmfile_free(ratingTag.ratingInfo);
468
469         return MMFILE_UTIL_FAIL;
470 }
471
472
473 static int GetClassficationFromClsfTagBox(MMFileFormatContext *formatContext, MMFileIOHandle *fp, MMFILE_MP4_BASIC_BOX_HEADER *basic_header)
474 {
475         int classinfoLen = 0;
476         int readed = 0;
477         char *temp_text = NULL;
478         MMFILE_3GP_CLASSIFICATION_TAGBOX classTag = {0, };
479
480         if (!formatContext || !fp || !basic_header) {
481                 debug_error(DEBUG, "invalid param\n");
482                 return MMFILE_UTIL_FAIL;
483         }
484
485         readed = mmfile_read(fp, (unsigned char *)&classTag, MMFILE_3GP_CLASS_TAGBOX_LEN);
486         if (readed != MMFILE_3GP_CLASS_TAGBOX_LEN) {
487                 debug_error(DEBUG, "read classification tag header fail\n");
488                 goto exception;
489         }
490
491
492         classinfoLen = basic_header->size - MMFILE_MP4_BASIC_BOX_HEADER_LEN - MMFILE_3GP_CLASS_TAGBOX_LEN;
493         if (classinfoLen == 1) {
494                 debug_error(DEBUG, "Classification Text is NULL\n");
495                 goto exception;
496         }
497
498         classTag.classificationInfo = mmfile_malloc(classinfoLen);
499         if (!classTag.classificationInfo) {
500                 debug_error(DEBUG, "class info error\n");
501                 goto exception;
502         }
503
504         readed = mmfile_read(fp, (unsigned char *)classTag.classificationInfo, classinfoLen);
505         if (readed != classinfoLen) {
506                 debug_error(DEBUG, "read class info string fail\n");
507                 goto exception;
508         }
509
510         /* check BOM char */
511         if ((classTag.classificationInfo[0] == 0xFE) && (classTag.classificationInfo[1] == 0xFF)) {
512                 /* this char is UTF-16 */
513                 unsigned int bytes_written = 0;
514                 temp_text = mmfile_string_convert((const char *)&classTag.classificationInfo[2], readed - 2, "UTF-8", "UTF-16", NULL, (unsigned int *)&bytes_written);
515         } else {
516                 temp_text = mmfile_strdup((const char *)classTag.classificationInfo);
517         }
518
519         if (!formatContext->classification) {
520                 formatContext->classification = temp_text;
521         } else {
522                 mmfile_free(temp_text);
523         }
524
525         mmfile_free(classTag.classificationInfo);
526         mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
527
528         return MMFILE_UTIL_SUCCESS;
529
530 exception:
531         mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
532         mmfile_free(classTag.classificationInfo);
533
534         return MMFILE_UTIL_FAIL;
535 }
536
537 /**
538  * The Location Information box
539  * --------------------+-------------------+-----------------------------------+------
540  * Field                                Type                            Details                                                         Value
541  * --------------------+-------------------+-----------------------------------+------
542  * BoxHeader.Size               Unsigned int(32)
543  * BoxHeader.Type               Unsigned int(32)                                                                                'loci'
544  * BoxHeader.Version    Unsigned int(8)                                                                                 0
545  * BoxHeader.Flags              Bit(24)                                                                                                 0
546  * Pad                                  Bit(1)                                                                                                  0
547  * Language                             Unsigned int(5)[3]      Packed ISO-639-2/T language code
548  * Name                                 String                          Text of place name
549  * Role                                 Unsigned int(8)         Non-negative value indicating role
550  *                                                                                      of location
551  * Longitude                    Unsigned int(32)        Fixed-point value of the longitude
552  * Latitude                             Unsigned int(32)        Fixed-point value of the latitude
553  * Altitude                             Unsigned int(32)        Fixed-point value of the Altitude
554  * Astronomical_body    String                          Text of astronomical body
555  * Additional_notes             String                          Text of additional location-related
556  *                                                                                      information
557  * --------------------+-------------------+-----------------------------------+------
558  */
559 static int _get_char_position(unsigned char *src, char ch, int max)
560 {
561         int i;
562         for (i = 0; i < max; i++) {
563                 if (*(src + i) == ch)
564                         return i;
565         }
566
567         return -1;
568 }
569
570 static int GetLocationFromLociTagBox(MMFileFormatContext *formatContext, MMFileIOHandle *fp, MMFILE_MP4_BASIC_BOX_HEADER *basic_header)
571 {
572
573         MMFILE_3GP_LOCATION_TAGBOX lociTag = {0, };
574         int readed = 0;
575         int bufferLen = 0;
576         unsigned char *buffer = NULL;
577         unsigned char *p = NULL;
578         int pos = 0;
579         unsigned int bytes_written = 0;
580         unsigned int name_sz = 0;
581         unsigned int astro_sz = 0;
582
583         int ilong, ilati, ialti;
584         float flong, flati, falti;
585
586
587         if (!formatContext || !fp || !basic_header) {
588                 debug_error(DEBUG, "invalid param\n");
589                 return MMFILE_UTIL_FAIL;
590         }
591
592         readed = mmfile_read(fp, (unsigned char *)&lociTag, 6);  /*6 = version + flag + pad + language */
593         if (readed != 6) {
594                 debug_error(DEBUG, "read location tag header fail\n");
595                 goto exception;
596         }
597
598         /*buffer len = name + role + ... + additional notes length */
599         bufferLen = basic_header->size - MMFILE_MP4_BASIC_BOX_HEADER_LEN - 6;
600         if (bufferLen < 1) {
601                 debug_error(DEBUG, "too small buffer\n");
602                 goto exception;
603         }
604
605         buffer = mmfile_malloc(bufferLen);
606         if (!buffer) {
607                 debug_error(DEBUG, "buffer malloc error\n");
608                 goto exception;
609         }
610
611         readed = mmfile_read(fp, (unsigned char *)buffer, bufferLen);
612         if (readed != bufferLen) {
613                 debug_error(DEBUG, "read location tag fail\n");
614                 goto exception;
615         }
616         p = buffer;
617
618         /*name*/
619         pos = _get_char_position(p, '\0', readed - (1 + 4 + 4 + 4 + 2));
620         if (pos >= 0) {
621                 if (p[0] == 0xFE && p[1] == 0xFF) {
622                         lociTag.name = (unsigned char *)mmfile_string_convert((const char *)(p + 2), pos - 2, "UTF-8", "UTF-16", NULL, (unsigned int *)&bytes_written);
623                 } else {
624                         lociTag.name = (unsigned char *)mmfile_strdup((const char *)p);
625                 }
626         } else {
627                 goto exception;
628         }
629         name_sz = pos + 1;
630         p += (pos + 1);
631
632         /*role*/
633         lociTag.role = *p;
634         p++;
635
636         debug_msg(RELEASE, "long: 0x%02X 0x%02X 0x%02X 0x%02X \n", *(p + 0), *(p + 1), *(p + 2), *(p + 3));
637         debug_msg(RELEASE, "lati: 0x%02X 0x%02X 0x%02X 0x%02X \n", *(p + 4), *(p + 5), *(p + 6), *(p + 7));
638         debug_msg(RELEASE, "alti: 0x%02X 0x%02X 0x%02X 0x%02X \n", *(p + 8), *(p + 9), *(p + 10), *(p + 11));
639
640         ilong = mmfile_io_be_uint32(*(unsigned int *)p);
641         ilati = mmfile_io_be_uint32(*(unsigned int *)(p + 4));
642         ialti = mmfile_io_be_uint32(*(unsigned int *)(p + 8));
643
644         flong = (float)ilong / (1 << 16);
645         flati = (float)ilati / (1 << 16);
646         falti = (float)ialti / (1 << 16);
647
648         /*longitude*/
649         lociTag.longitude = flong;
650         /*latitude*/
651         lociTag.latitude = flati;
652         /*altitude*/
653         lociTag.altitude = falti;
654
655         p += 12;
656
657         /*astronomical body*/
658         pos = _get_char_position(p, '\0', readed - (name_sz + 1 + 4 + 4 + 4 + 1));
659         if (pos >= 0) {
660                 if (p[0] == 0xFE && p[1] == 0xFF) {
661                         lociTag.astronomical_body = (unsigned char *)mmfile_string_convert((const char *)(p + 2), pos - 2, "UTF-8", "UTF-16", NULL, (unsigned int *)&bytes_written);
662                 } else {
663                         lociTag.astronomical_body = (unsigned char *)mmfile_strdup((const char *)p);
664                 }
665         } else {
666                 goto exception;
667         }
668         astro_sz = pos + 1;
669         p += (pos + 1);
670
671         /*additional notes*/
672         pos = _get_char_position(p, '\0', readed - (name_sz + 1 + 4 + 4 + 4 + astro_sz));
673         if (pos >= 0) {
674                 if (p[0] == 0xFE && p[1] == 0xFF) {
675                         lociTag.additional_notes = (unsigned char *)mmfile_string_convert((const char *)(p + 2), pos - 2, "UTF-8", "UTF-16", NULL, (unsigned int *)&bytes_written);
676                 } else {
677                         lociTag.additional_notes = (unsigned char *)mmfile_strdup((const char *)p);
678                 }
679         } else {
680                 goto exception;
681         }
682
683         debug_msg(RELEASE, "** Location Information **\n");
684         debug_msg(RELEASE, "Name             : %s\n", lociTag.name);
685         debug_msg(RELEASE, "Role             : %d (0: shooting, 1: real, 2: fictional, other: reserved)\n", lociTag.role);
686         debug_msg(RELEASE, "Longitude        : %16.16f\n", lociTag.longitude);
687         debug_msg(RELEASE, "Latitude         : %16.16f\n", lociTag.latitude);
688         debug_msg(RELEASE, "Altitude         : %16.16f\n", lociTag.altitude);
689         debug_msg(RELEASE, "Astronomical body: %s\n", lociTag.astronomical_body);
690         debug_msg(RELEASE, "Additional notes : %s\n", lociTag.additional_notes);
691
692         formatContext->longitude = lociTag.longitude;
693         formatContext->latitude = lociTag.latitude;
694         formatContext->altitude = lociTag.altitude;
695
696         mmfile_free(buffer);
697         mmfile_free(lociTag.name);
698         mmfile_free(lociTag.astronomical_body);
699         mmfile_free(lociTag.additional_notes);
700
701         mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
702         return MMFILE_UTIL_SUCCESS;
703
704 exception:
705         mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
706         mmfile_free(buffer);
707         mmfile_free(lociTag.name);
708         mmfile_free(lociTag.astronomical_body);
709         mmfile_free(lociTag.additional_notes);
710
711         return MMFILE_UTIL_FAIL;
712 }
713
714 static int GetSAUTInfoFromSMTATagBox(MMFileFormatContext *formatContext, MMFileIOHandle *fp, MMFILE_MP4_BASIC_BOX_HEADER *basic_header)
715 {
716         MMFILE_M4A_SMTA_TAGBOX smtaTag = {0, };
717         int readed = 0;
718
719         if (!formatContext || !fp || !basic_header) {
720                 debug_error(DEBUG, "invalid param\n");
721                 return MMFILE_UTIL_FAIL;
722         }
723
724         readed = mmfile_read(fp, (unsigned char *)&smtaTag, sizeof(MMFILE_M4A_SMTA_TAGBOX));
725         if (readed != sizeof(MMFILE_M4A_SMTA_TAGBOX)) {
726                 debug_error(DEBUG, "read smta tag header fail\n");
727                 goto exception;
728         }
729
730         smtaTag.length = mmfile_io_be_uint32(smtaTag.length);
731         smtaTag.value = mmfile_io_be_uint32(smtaTag.value);
732
733         debug_msg(RELEASE, "Len : 0x%x", smtaTag.length);
734         debug_msg(RELEASE, "Saut : 0x%x 0x%x 0x%x 0x%x", smtaTag.saut[0], smtaTag.saut[1], smtaTag.saut[2], smtaTag.saut[3]);
735         debug_msg(RELEASE, "Value : 0x%x", smtaTag.value);
736
737         if (smtaTag.saut[0] == 's'
738             && smtaTag.saut[1] == 'a'
739             && smtaTag.saut[2] == 'u'
740             && smtaTag.saut[3] == 't') {
741                 if (smtaTag.value == 0x01) {
742                         debug_msg(RELEASE, "This has saut tag and valid value");
743                         formatContext->smta = 1;
744                 } else {
745                         debug_error(DEBUG, "This has saut tag and but invalid value");
746                         goto exception;
747                 }
748         } else {
749                 debug_error(DEBUG, "This hasn't saut tag and valid value");
750                 goto exception;
751         }
752
753         return MMFILE_UTIL_SUCCESS;
754
755 exception:
756         mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
757
758         return MMFILE_UTIL_FAIL;
759 }
760
761 static int GetValueFromCDISTagBox(MMFileFormatContext *formatContext, MMFileIOHandle *fp, MMFILE_MP4_BASIC_BOX_HEADER *basic_header)
762 {
763         unsigned int value = 0;
764         int readed = 0;
765
766         if (!formatContext || !fp || !basic_header) {
767                 debug_error(DEBUG, "invalid param\n");
768                 return MMFILE_UTIL_FAIL;
769         }
770
771         readed = mmfile_read(fp, (unsigned char *)&value, sizeof(unsigned int));
772         if (readed != sizeof(unsigned int)) {
773                 debug_error(DEBUG, "read cdis tag header fail\n");
774                 goto exception;
775         }
776
777         value = mmfile_io_be_uint32(value);
778
779         debug_msg(RELEASE, "Value : 0x%x", value);
780
781         if (value == 0x01) {
782                 debug_msg(RELEASE, "This has cdis tag and valid value");
783                 formatContext->cdis = 1;
784         } else {
785                 debug_error(DEBUG, "This has cdis tag and but invalid value");
786                 goto exception;
787         }
788
789         return MMFILE_UTIL_SUCCESS;
790
791 exception:
792         mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
793
794         return MMFILE_UTIL_FAIL;
795 }
796
797 static int GetTagFromMetaBox(MMFileFormatContext *formatContext, MMFileIOHandle *fp, MMFILE_MP4_BASIC_BOX_HEADER *basic_header)
798 {
799         int readed = 0;
800         MMFILE_MP4_BASIC_BOX_HEADER hdlrBoxHeader = {0, };
801         MMFILE_MP4_BASIC_BOX_HEADER id3v2BoxHeader = {0, };
802         MMFILE_3GP_ID3V2_BOX id3v2Box = {0, };
803         AvFileContentInfo tagInfo = {0, };
804         unsigned char tagVersion = 0;
805         bool versionCheck = false;
806         int id3v2Len = 0;
807         unsigned int meta_version = 0;
808         MMFILE_3GP_HANDLER_BOX hdlrBox = {0, };
809         unsigned int encSize = 0;
810         int id3_meta = 0;
811 #ifdef ENABLE_ITUNES_META /* We don't support itunes meta now. so this is not defined yet */
812         int iTunes_meta = 0;
813 #endif
814
815         /* meta box */
816         readed = mmfile_read(fp, (unsigned char *)&meta_version, 4);
817         if (readed != 4) {
818                 debug_error(DEBUG, "read meta box version\n");
819                 goto exception;
820         }
821
822         /* hdlr box */
823         readed = mmfile_read(fp, (unsigned char *)&hdlrBoxHeader, MMFILE_MP4_BASIC_BOX_HEADER_LEN);
824         if (readed != MMFILE_MP4_BASIC_BOX_HEADER_LEN) {
825                 debug_error(DEBUG, "read hdlr box header\n");
826                 goto exception;
827         }
828
829         if (hdlrBoxHeader.type != FOURCC('h', 'd', 'l', 'r')) {
830                 debug_warning(DEBUG, "meta type is not hdlr\n");
831                 goto exception;
832         }
833
834         hdlrBoxHeader.size = mmfile_io_be_uint32(hdlrBoxHeader.size);
835         hdlrBoxHeader.type = mmfile_io_le_uint32(hdlrBoxHeader.type);
836
837         readed = mmfile_read(fp, (unsigned char *)&hdlrBox, MMFILE_3GP_HANDLER_BOX_LEN);
838         if (readed != MMFILE_3GP_HANDLER_BOX_LEN) {
839                 debug_error(DEBUG, "read hdlr box\n");
840                 goto exception;
841         }
842
843         hdlrBox.handler_type = mmfile_io_le_uint32(hdlrBox.handler_type);
844
845         /**
846          * check tag type (ID3v2 or iTunes)
847          */
848         if (hdlrBox.handler_type == FOURCC('I', 'D', '3', '2')) {
849                 debug_msg(RELEASE, "ID3v2 tag detected.\n");
850
851                 id3_meta = 1;
852 #ifdef ENABLE_ITUNES_META
853                 iTunes_meta = 0;
854 #endif
855         } else if (hdlrBox.handler_type == FOURCC('m', 'd', 'i', 'r') &&
856                                 mmfile_io_le_uint32(hdlrBox.reserved[0]) == FOURCC('a', 'p', 'p', 'l')) {
857
858                 debug_msg(RELEASE, "Apple iTunes tag detected by mdir.\n");
859
860 #ifdef ENABLE_ITUNES_META
861                 iTunes_meta = 1;
862 #endif
863         } else {
864                 debug_warning(DEBUG, "unknown meta type. 4CC:[%c%c%c%c]\n", ((char *)&hdlrBox.handler_type)[0],
865                                         ((char *)&hdlrBox.handler_type)[1],
866                                         ((char *)&hdlrBox.handler_type)[2],
867                                         ((char *)&hdlrBox.handler_type)[3]);
868                 /*goto exception; */
869         }
870
871 #ifdef ENABLE_ITUNES_META
872         if (!id3_meta && !iTunes_meta) {
873                 /*Check ilst.
874                 APPLE meta data for iTunes reader = 'mdir.' so if handler type is 'mdir', this content may has itunes meta.
875                 most of contents has 'mdir' + 'appl'. but some contents just has 'mdir'
876                 but 'ilst' is meta for iTunes. so find 'ilst' is more correct to check if this contents has iTunes meta or not.*/
877
878                 const char *ilst_box = "ilst";
879                 int buf_size = strlen(ilst_box);
880
881                 unsigned char read_buf[buf_size + 1];
882                 memset(read_buf, 0x00, buf_size + 1);
883
884                 /* skip hdlr box */
885                 mmfile_seek(fp, hdlrBoxHeader.size - MMFILE_MP4_BASIC_BOX_HEADER_LEN - MMFILE_3GP_HANDLER_BOX_LEN + 4, SEEK_CUR);       /*+4 is hdlr size field */
886
887                 readed = mmfile_read(fp, read_buf, buf_size);   /* to find 'ilst' */
888                 if (readed != buf_size) {
889                         debug_error(DEBUG, "read fail [%d]\n", readed);
890                         goto exception;
891                 }
892
893                 if (read_buf[0] == 'i' && read_buf[1] == 'l' && read_buf[2] == 's' && read_buf[3] == 't') {
894                         debug_msg(RELEASE, "Apple iTunes tag detected by ilst.\n");
895                         iTunes_meta = 1;
896                 }
897         }
898 #endif
899
900 #ifdef ENABLE_ITUNES_META
901         if (iTunes_meta) {
902                 /**
903                  * iTunes (Cover[?ovr] & Track[trkn] only extract!) + Genre/Artist : Added 2010.10.27,28
904                  *
905                  *  4cc   : 4byte
906                  *        : 4byte       size
907                  * 'data' : 4byte
908                  *        : 4byte       type
909                  *        : 4byte       unknown
910                  */
911 #define _ITUNES_READ_BUF_SZ             20
912 #define _ITUNES_TRACK_NUM_SZ    4
913 #define _ITUNES_GENRE_NUM_SZ    4
914 #define _ITUNES_COVER_TYPE_JPEG 13
915 #define _ITUNES_COVER_TYPE_PNG          14
916
917                 unsigned char read_buf[_ITUNES_READ_BUF_SZ];
918                 int i = 0;
919                 int cover_sz = 0, cover_type = 0, cover_found = 0;
920                 /* int track_found = 0; */ /* , track_num = 0; */
921                 /* int genre_found = 0; */ /* , genre_index = 0; */
922                 /* int artist_found = 0; */ /* , artist_sz = 0; */
923                 int limit = basic_header->size - hdlrBoxHeader.size;
924                 long long cover_offset = 0; /*, track_offset =0, genre_offset = 0, artist_offset = 0; */
925
926                 /* 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++) { */
927                 for (i = 0; (i < limit) && (cover_found == 0) ; i++) {
928                         readed = mmfile_read(fp, read_buf, _ITUNES_READ_BUF_SZ);
929                         if (readed != _ITUNES_READ_BUF_SZ)
930                                 goto exception;
931
932                         /*ffmpeg extract artist, tracknum, genre and cover image. see mov_read_udta_string().
933                         but ffmpeg does not support strange cover image.
934                         only support covr type 0xd(JPEG), 0xe(PNG), 0x1b(BMP). but we support other type*/
935 #if 0
936                         /**
937                          * Artist : Added 2010.10.28
938                          */
939                         if (artist_found == 0 &&
940                             read_buf[0] == 0xa9 && read_buf[1] == 'A' && read_buf[2] == 'R' && read_buf[3] == 'T' &&
941                             read_buf[8] == 'd' && read_buf[9] == 'a' && read_buf[10] == 't' && read_buf[11] == 'a') {
942
943                                 artist_found = 1;
944                                 artist_offset = mmfile_tell(fp);
945                                 artist_sz = mmfile_io_be_uint32(*(int *)(read_buf + 4)) - 16; /* atom len(4)+data(4)+atom verion(1)+flag(3)+null(4) = 16 */
946
947                                 debug_msg(RELEASE, "----------------------------------- artist found, offset=[%lld], size=[%d]\n", artist_offset, artist_sz);
948                         }
949
950                         /**
951                          * Track number
952                          */
953                         if (track_found == 0 &&
954                             read_buf[0] == 't' && read_buf[1] == 'r' && read_buf[2] == 'k' && read_buf[3] == 'n' &&
955                             read_buf[8] == 'd' && read_buf[9] == 'a' && read_buf[10] == 't' && read_buf[11] == 'a') {
956
957                                 track_found = 1;
958                                 track_offset = mmfile_tell(fp);
959
960                                 debug_msg(RELEASE, "----------------------------------- Track found, offset=[%lld]\n", track_offset);
961                         }
962
963                         /**
964                          * Genre : Added 2010.10.27
965                          */
966                         /*ffmpeg extract genre but only (0xa9,'g','e','n'). see mov_read_udta_string()*/
967                         if (genre_found == 0 &&
968                             read_buf[0] == 'g' && read_buf[1] == 'n' && read_buf[2] == 'r' && read_buf[3] == 'e' &&
969                             read_buf[8] == 'd' && read_buf[9] == 'a' && read_buf[10] == 't' && read_buf[11] == 'a') {
970
971                                 genre_found = 1;
972                                 genre_offset = mmfile_tell(fp);
973
974                                 debug_msg(RELEASE, "----------------------------------- genre found, offset=[%lld]\n", genre_offset);
975                         }
976 #endif
977
978                         /**
979                          * Cover image
980                          */
981
982                         if (cover_found == 0 &&
983                             read_buf[0] == 'c' && read_buf[1] == 'o' && read_buf[2] == 'v' && read_buf[3] == 'r' &&
984                             read_buf[8] == 'd' && read_buf[9] == 'a' && read_buf[10] == 't' && read_buf[11] == 'a') {
985
986                                 cover_found = 1;
987                                 cover_sz = mmfile_io_be_uint32(*(int *)(read_buf + 4)) - 12;
988                                 cover_type = mmfile_io_be_uint32(*(int *)(read_buf + 12));
989
990                                 cover_offset = mmfile_tell(fp);
991
992                                 debug_msg(RELEASE, "----------------------------------- cover_found found,  offset=[%lld]\n", cover_offset);
993                         }
994
995                         mmfile_seek(fp, -(_ITUNES_READ_BUF_SZ - 1), SEEK_CUR);  /*FIXME: poor search*/
996                 } /*loop*/
997
998                 /*ffmpeg extract artist, tracknum, excep cover image. see mov_read_udta_string()*/
999 #if 0
1000                 if (artist_found) {
1001                         if (artist_sz > 0) {
1002                                 mmfile_seek(fp, artist_offset, SEEK_SET);
1003
1004                                 if (formatContext->artist) {
1005                                         debug_msg(RELEASE, "----------------------------------- previous artist was [%s] \n", formatContext->artist);
1006                                         free(formatContext->artist);
1007                                 }
1008
1009                                 debug_msg(RELEASE, "----------------------------------- new artist will be allocated with size (len+1) [%d] \n", artist_sz + 1);
1010                                 formatContext->artist = mmfile_malloc(artist_sz + 1);
1011
1012                                 if (formatContext->artist) {
1013                                         readed = mmfile_read(fp, (unsigned char *)formatContext->artist, artist_sz);
1014                                         formatContext->artist[artist_sz] = '\0';
1015
1016                                         debug_msg(RELEASE, "----------------------------------- new artist is [%s] \n", formatContext->artist);
1017
1018                                         if (readed != artist_sz) {
1019                                                 debug_error(DEBUG, "failed to read. ret = %d, in = %d\n", readed, artist_sz);
1020                                                 mmfile_free(formatContext->artist);
1021                                         }
1022                                 }
1023                         }
1024                 }
1025
1026                 if (track_found) {
1027                         mmfile_seek(fp, track_offset, SEEK_SET);
1028                         readed = mmfile_read(fp, read_buf, _ITUNES_TRACK_NUM_SZ);
1029                         if (readed != _ITUNES_TRACK_NUM_SZ) {
1030                                 debug_error(DEBUG, "failed to read. ret = %d, in = %d\n", readed, _ITUNES_TRACK_NUM_SZ);
1031                         } else {
1032                                 track_num = mmfile_io_be_uint32(*(int *)read_buf);
1033                                 if (!formatContext->tagTrackNum) {
1034                                         memset(read_buf, 0x00, _ITUNES_READ_BUF_SZ);
1035                                         snprintf((char *)read_buf, sizeof(read_buf), "%d", track_num);
1036                                         formatContext->tagTrackNum = mmfile_strdup((const char *)read_buf);
1037                                 }
1038                         }
1039                 }
1040
1041                 if (genre_found) {
1042                         mmfile_seek(fp, genre_offset, SEEK_SET);
1043                         readed = mmfile_read(fp, read_buf, _ITUNES_GENRE_NUM_SZ);
1044                         if (readed != _ITUNES_GENRE_NUM_SZ) {
1045                                 debug_error(DEBUG, "failed to read. ret = %d, in = %d\n", readed, _ITUNES_GENRE_NUM_SZ);
1046                         } else {
1047                                 genre_index = mmfile_io_be_uint16(*(int *)read_buf);
1048                                 debug_msg(RELEASE, "genre index=[%d] \n", genre_index);
1049
1050                                 if (genre_index > 0 && genre_index < GENRE_COUNT)       {
1051                                         if (!formatContext->genre) {
1052                                                 memset(read_buf, 0x00, _ITUNES_READ_BUF_SZ);
1053                                                 snprintf((char *)read_buf, sizeof(read_buf), "%s", MpegAudio_Genre[genre_index - 1]);
1054                                                 debug_msg(RELEASE, "genre string=[%s] \n", read_buf);
1055                                                 formatContext->genre = mmfile_strdup((const char *)read_buf);
1056                                         }
1057                                 }
1058                         }
1059                 }
1060 #endif
1061
1062                 /*
1063                         1) below spec is in "iTunes Package Asset Specification 4.3" published by apple.
1064                         Music Cover Art Image Profile
1065                         - TIFF with ".tif" extension (32-bit uncompressed), JPEG with ".jpg" extension (quality unconstrained), or PNG with ".png" extension
1066                         - RGB (screen standard)
1067                         - Minimum size of 600 x 600 pixels
1068                         - Images must be at least 72 dpi
1069
1070                         2)I found below info from google.
1071                         cover image flag : JPEG (13, 0xd), PNG (14, 0xe)
1072
1073                         3)So, FIXME when cover image format is tif!
1074                 */
1075                 if (cover_found) {
1076                         if (cover_sz > 0) {
1077                                 mmfile_seek(fp, cover_offset, SEEK_SET);
1078
1079                                 formatContext->artwork = mmfile_malloc(cover_sz);
1080                                 formatContext->artworkSize = cover_sz;
1081                                 if (cover_type == _ITUNES_COVER_TYPE_JPEG) {
1082                                         formatContext->artworkMime = mmfile_strdup("image/jpeg");
1083                                 } else if (cover_type == _ITUNES_COVER_TYPE_PNG) {
1084                                         formatContext->artworkMime = mmfile_strdup("image/png");
1085                                         /*} else if(cover_type == _ITUNES_COVER_TYPE_TIF) {
1086                                                 formatContext->artworkMime = mmfile_strdup("image/tif");*/
1087                                 } else {
1088                                         debug_warning(DEBUG, "Not proper cover image type, but set to jpeg. cover_type[%d]", cover_type);
1089                                         formatContext->artworkMime = mmfile_strdup("image/jpeg");
1090                                 }
1091
1092                                 if (formatContext->artwork) {
1093                                         readed = mmfile_read(fp, formatContext->artwork, cover_sz);
1094                                         if (readed != cover_sz) {
1095                                                 debug_error(DEBUG, "failed to read. ret = %d, in = %d\n", readed, cover_sz);
1096                                                 mmfile_free(formatContext->artwork);
1097                                                 formatContext->artworkSize = 0;
1098                                                 mmfile_free(formatContext->artworkMime);
1099                                         }
1100                                 }
1101                         }
1102                 }
1103
1104                 /*reset seek position*/
1105                 mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
1106
1107                 return MMFILE_UTIL_SUCCESS;
1108
1109         } else
1110 #endif
1111                 if (id3_meta) {
1112                         /**
1113                          * ID3v2
1114                          */
1115                         /* skip hdlr box name */
1116                         mmfile_seek(fp, hdlrBoxHeader.size - MMFILE_MP4_BASIC_BOX_HEADER_LEN - MMFILE_3GP_HANDLER_BOX_LEN, SEEK_CUR);
1117
1118                         /* id3 tag box */
1119                         readed = mmfile_read(fp, (unsigned char *)&id3v2BoxHeader, MMFILE_MP4_BASIC_BOX_HEADER_LEN);
1120                         if (readed != MMFILE_MP4_BASIC_BOX_HEADER_LEN) {
1121                                 debug_error(DEBUG, "read id3v2 box header\n");
1122                                 goto exception;
1123                         }
1124
1125                         id3v2BoxHeader.size = mmfile_io_be_uint32(id3v2BoxHeader.size);
1126                         id3v2BoxHeader.type = mmfile_io_le_uint32(id3v2BoxHeader.type);
1127
1128                         if (id3v2BoxHeader.type != FOURCC('I', 'D', '3', '2')) {
1129                                 debug_warning(DEBUG, "meta type is not id3v2\n");
1130                                 goto exception;
1131                         }
1132
1133                         readed = mmfile_read(fp, (unsigned char *)&id3v2Box, MMFILE_3GP_ID3V2_BOX_LEN);
1134                         if (readed != MMFILE_3GP_ID3V2_BOX_LEN) {
1135                                 debug_error(DEBUG, "read id3v2 box\n");
1136                                 goto exception;
1137                         }
1138
1139                         id3v2Len = id3v2BoxHeader.size - MMFILE_MP4_BASIC_BOX_HEADER_LEN - MMFILE_3GP_ID3V2_BOX_LEN;
1140
1141                         id3v2Box.id3v2Data = mmfile_malloc(id3v2Len);
1142                         if (!id3v2Box.id3v2Data) {
1143                                 debug_error(DEBUG, "malloc id3tag data error\n");
1144                                 goto exception;
1145                         }
1146
1147                         readed = mmfile_read(fp, (unsigned char *)id3v2Box.id3v2Data, id3v2Len);
1148                         if (readed != id3v2Len) {
1149                                 debug_error(DEBUG, "read id3tag data error\n");
1150                                 goto exception;
1151                         }
1152
1153                         /* check id3v2 */
1154                         if (!IS_ID3V2_TAG(id3v2Box.id3v2Data)) {
1155                                 debug_error(DEBUG, "it is not id3tag\n");
1156                                 goto exception;
1157                         }
1158
1159                         if (id3v2Box.id3v2Data[3] == 0xFF ||  id3v2Box.id3v2Data[4] == 0xFF ||
1160                             id3v2Box.id3v2Data[6] >= 0x80 ||  id3v2Box.id3v2Data[7] >= 0x80 ||
1161                             id3v2Box.id3v2Data[8] >= 0x80 ||  id3v2Box.id3v2Data[9] >= 0x80) {
1162                                 debug_error(DEBUG, "it is not valid id3tag\n");
1163                                 goto exception;
1164                         }
1165
1166                         tagVersion = id3v2Box.id3v2Data[3];
1167                         if (tagVersion > 4) {
1168                                 debug_error(DEBUG, "tag vesion is too high\n");
1169                                 goto exception;
1170                         }
1171
1172                         encSize = mmfile_io_le_uint32((unsigned int)&id3v2Box.id3v2Data[6]);
1173                         tagInfo.tagV2Info.tagLen = MP3_TAGv2_HEADER_LEN;
1174                         tagInfo.tagV2Info.tagLen += (((encSize & 0x0000007F) >> 0) | ((encSize & 0x00007F00) >> 1) | ((encSize & 0x007F0000) >> 2) | ((encSize & 0x7F000000) >> 3));
1175                         tagInfo.tagV2Info.tagVersion = tagVersion;
1176                         tagInfo.fileLen = id3v2Len;
1177
1178                         /* set id3v2 data to formatContext */
1179                         switch (tagVersion) {
1180                                 case 2: {
1181                                                 versionCheck = mm_file_id3tag_parse_v222(&tagInfo, id3v2Box.id3v2Data);
1182                                                 break;
1183                                         }
1184                                 case 3: {
1185                                                 versionCheck = mm_file_id3tag_parse_v223(&tagInfo, id3v2Box.id3v2Data);
1186                                                 break;
1187                                         }
1188                                 case 4: {
1189                                                 versionCheck = mm_file_id3tag_parse_v224(&tagInfo, id3v2Box.id3v2Data);
1190                                                 break;
1191                                         }
1192                                 case 1:
1193                                 default: {
1194                                                 debug_error(DEBUG, "tag vesion is not support\n");
1195                                                 versionCheck = false;
1196                                                 break;
1197                                         }
1198                         }
1199
1200                         if (versionCheck == false) {
1201                                 debug_error(DEBUG, "tag parsing is fail\n");
1202                                 goto exception;
1203                         }
1204
1205                         if (!formatContext->title)          formatContext->title = mmfile_strdup((const char *)tagInfo.pTitle);
1206                         if (!formatContext->artist)         formatContext->artist = mmfile_strdup((const char *)tagInfo.pArtist);
1207                         if (!formatContext->author)         formatContext->author = mmfile_strdup((const char *)tagInfo.pAuthor);
1208                         if (!formatContext->copyright)      formatContext->copyright = mmfile_strdup((const char *)tagInfo.pCopyright);
1209                         if (!formatContext->comment)        formatContext->comment = mmfile_strdup((const char *)tagInfo.pComment);
1210                         if (!formatContext->album)          formatContext->album = mmfile_strdup((const char *)tagInfo.pAlbum);
1211                         if (!formatContext->album_artist)   formatContext->album_artist = mmfile_strdup((const char *)tagInfo.pAlbum_Artist);
1212                         if (!formatContext->year)           formatContext->year = mmfile_strdup((const char *)tagInfo.pYear);
1213                         if (!formatContext->genre)          formatContext->genre = mmfile_strdup((const char *)tagInfo.pGenre);
1214                         if (!formatContext->tagTrackNum)    formatContext->tagTrackNum = mmfile_strdup((const char *)tagInfo.pTrackNum);
1215                         if (!formatContext->composer)       formatContext->composer = mmfile_strdup((const char *)tagInfo.pComposer);
1216                         if (!formatContext->classification) formatContext->classification = mmfile_strdup((const char *)tagInfo.pContentGroup);
1217                         if (!formatContext->conductor)      formatContext->conductor = mmfile_strdup((const char *)tagInfo.pConductor);
1218
1219                         formatContext->artwork = mmfile_malloc(tagInfo.imageInfo.imageLen);
1220                         if ((tagInfo.imageInfo.imageLen > 0) && formatContext->artwork) {
1221                                 formatContext->artworkSize = tagInfo.imageInfo.imageLen;
1222                                 memcpy(formatContext->artwork, tagInfo.imageInfo.pImageBuf, tagInfo.imageInfo.imageLen);
1223                         }
1224
1225                         mm_file_free_AvFileContentInfo(&tagInfo);
1226                         mmfile_free(id3v2Box.id3v2Data);
1227
1228                         /*reset seek position*/
1229                         mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
1230
1231                         return MMFILE_UTIL_SUCCESS;
1232
1233                 }
1234
1235
1236 exception:
1237         mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
1238         mmfile_free(id3v2Box.id3v2Data);
1239         mm_file_free_AvFileContentInfo(&tagInfo);
1240
1241         return MMFILE_UTIL_FAIL;
1242 }
1243
1244 static int g_junk_counter_limit = 0;
1245 static int GetJunkCounterLimit(void)
1246 {
1247         dictionary *dict = NULL;
1248         int data = 0;
1249
1250         dict = iniparser_load(MM_FILE_INI_PATH);
1251         if (!dict) {
1252                 debug_error(DEBUG, "%s load failed", MM_FILE_INI_PATH);
1253                 return -1;
1254         }
1255
1256         data = iniparser_getint(dict, "mm-file-config:junk_counter_limit", 0);
1257         debug_msg(DEBUG, "mm-file-config:junk_counter_limit= %u", data);
1258
1259         iniparser_freedict(dict);
1260
1261         return data;
1262 }
1263
1264 #define BIG_CONTENT_BOX_SIZE_LEN 8
1265 EXPORT_API int MMFileUtilGetMetaDataFromMP4(MMFileFormatContext *formatContext)
1266 {
1267         MMFileIOHandle *fp = NULL;
1268         int ret = 0;
1269         int readed;
1270         unsigned long long chunk_size = 0;
1271         long long moov_end = 0;
1272
1273         ret = mmfile_open(&fp, formatContext->uriFileName, MMFILE_RDONLY);
1274         if (ret == MMFILE_UTIL_FAIL) {
1275                 debug_error(DEBUG, "error: mmfile_open\n");
1276                 goto exit;
1277         }
1278
1279         MMFILE_MP4_BASIC_BOX_HEADER basic_header = {0, };
1280         basic_header.start_offset = mmfile_tell(fp);
1281
1282         int junk_counter = 0;
1283         if (g_junk_counter_limit == 0)
1284                 g_junk_counter_limit = GetJunkCounterLimit();
1285
1286         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)) {
1287                 basic_header.size = mmfile_io_be_uint32(basic_header.size);
1288                 basic_header.type = mmfile_io_le_uint32(basic_header.type);
1289
1290                 if (basic_header.size == 0) {
1291                         debug_warning(DEBUG, "header is invalid.\n");
1292                         basic_header.size = readed;
1293                         basic_header.type = 0;
1294                         chunk_size = basic_header.size;
1295
1296                         if ((moov_end != 0) && (moov_end < basic_header.start_offset))
1297                         {
1298                                 debug_msg(DEBUG, "found junk data but moov data already was extracted, so junk counter will be increase: %d", junk_counter);
1299                                 junk_counter++;
1300
1301                                 /* stop the loop for junk case. */
1302                                 if ((g_junk_counter_limit > 0) && (junk_counter > g_junk_counter_limit))
1303                                 {
1304                                         debug_msg(DEBUG, "stop the loop by junk-data checker");
1305                                         ret = MMFILE_UTIL_FAIL;
1306                                         continue;
1307                                 }
1308                         }
1309                 } else if (basic_header.size == 1) {
1310                         int i = 0;
1311                         unsigned char temp[BIG_CONTENT_BOX_SIZE_LEN] = {0, };
1312                         unsigned long long size = 0;
1313
1314                         mmfile_read(fp, (unsigned char *)&temp, BIG_CONTENT_BOX_SIZE_LEN);
1315
1316                         for(i = 0; i < BIG_CONTENT_BOX_SIZE_LEN; i++)
1317                                 size |= (unsigned long long)temp[i] << (BIG_CONTENT_BOX_SIZE_LEN - 1 - i) * BIG_CONTENT_BOX_SIZE_LEN;
1318                         chunk_size = size;
1319                         junk_counter = 0;
1320                 } else {
1321                         chunk_size = basic_header.size;
1322                         junk_counter = 0;
1323                 }
1324
1325                 switch (basic_header.type) {
1326                         case FOURCC('m', 'o', 'o', 'v'): {
1327                                         debug_msg(RELEASE, "MPEG4: [moov] SIZE: [%lld]Byte\n", chunk_size);
1328                                         moov_end = basic_header.start_offset + chunk_size;
1329                                         break;
1330                                 }
1331                         case FOURCC('u', 'd', 't', 'a'): {
1332                                         debug_msg(RELEASE, "MPEG4: [udat] SIZE: [%lld]Byte\n", chunk_size);
1333                                         break;
1334                                 }
1335                                 /*/////////////////////////////////////////////////////////////// */
1336                                 /*                  Extracting Tag Data                        // */
1337                                 /*/////////////////////////////////////////////////////////////// */
1338                         case FOURCC('t', 'i', 't', 'l'): {
1339                                         debug_msg(RELEASE, "MPEG4: [titl] SIZE: [%lld]Byte\n", chunk_size);
1340                                         GetStringFromTextTagBox(formatContext, fp, &basic_header, eMMFILE_3GP_TAG_TITLE);
1341                                         break;
1342                                 }
1343                         case FOURCC('d', 's', 'c', 'p'): {
1344                                         debug_msg(RELEASE, "MPEG4: [dscp] SIZE: [%lld]Byte\n", chunk_size);
1345                                         GetStringFromTextTagBox(formatContext, fp, &basic_header, eMMFILE_3GP_TAG_CAPTION);
1346                                         break;
1347                                 }
1348                         case FOURCC('c', 'p', 'r', 't'): {
1349                                         debug_msg(RELEASE, "MPEG4: [cprt] SIZE: [%lld]Byte\n", chunk_size);
1350                                         GetStringFromTextTagBox(formatContext, fp, &basic_header, eMMFILE_3GP_TAG_COPYRIGHT);
1351                                         break;
1352                                 }
1353                         case FOURCC('p', 'e', 'r', 'f'): {
1354                                         debug_msg(RELEASE, "MPEG4: [perf] SIZE: [%lld]Byte\n", chunk_size);
1355                                         GetStringFromTextTagBox(formatContext, fp, &basic_header, eMMFILE_3GP_TAG_PERFORMER);
1356                                         break;
1357                                 }
1358                         case FOURCC('a', 'u', 't', 'h'): {
1359                                         debug_msg(RELEASE, "MPEG4: [auth] SIZE: [%lld]Byte\n", chunk_size);
1360                                         GetStringFromTextTagBox(formatContext, fp, &basic_header, eMMFILE_3GP_TAG_AUTHOR);
1361                                         break;
1362                                 }
1363                         case FOURCC('g', 'n', 'r', 'e'): {
1364                                         debug_msg(RELEASE, "MPEG4: [gnre] SIZE: [%lld]Byte\n", chunk_size);
1365                                         GetStringFromTextTagBox(formatContext, fp, &basic_header, eMMFILE_3GP_TAG_GENRE);
1366                                         break;
1367                                 }
1368                         case FOURCC('a', 'l', 'b', 'm'): {
1369                                         debug_msg(RELEASE, "MPEG4: [albm] SIZE: [%lld]Byte\n", chunk_size);
1370                                         GetAlbumFromAlbumTagBox(formatContext, fp, &basic_header);
1371                                         break;
1372                                 }
1373                         case FOURCC('y', 'r', 'r', 'c'): {
1374                                         debug_msg(RELEASE, "MPEG4: [yrrc] SIZE: [%lld]Byte\n", chunk_size);
1375                                         GetYearFromYearTagBox(formatContext, fp, &basic_header);
1376                                         break;
1377                                 }
1378                         case FOURCC('r', 't', 'n', 'g'): {
1379                                         debug_msg(RELEASE, "MPEG4: [rtng] SIZE: [%lld]Byte\n", chunk_size);
1380                                         GetRatingFromRatingTagBox(formatContext, fp, &basic_header);  /* not use */
1381                                         break;
1382                                 }
1383                         case FOURCC('c', 'l', 's', 'f'): {
1384                                         debug_msg(RELEASE, "MPEG4: [clsf] SIZE: [%lld]Byte\n", chunk_size);
1385                                         GetClassficationFromClsfTagBox(formatContext, fp, &basic_header);
1386                                         break;
1387                                 }
1388                         case FOURCC('k', 'y', 'w', 'd'): {
1389                                         debug_msg(RELEASE, "MPEG4: [kywd] SIZE: [%lld]Byte\n", chunk_size);
1390                                         ret = mmfile_seek(fp, basic_header.start_offset + chunk_size, SEEK_SET);
1391                                         break;
1392                                 }
1393                         case FOURCC('l', 'o', 'c', 'i'): {
1394                                         debug_msg(RELEASE, "MPEG4: [loci] SIZE: [%lld]Byte\n", chunk_size);
1395                                         GetLocationFromLociTagBox(formatContext, fp, &basic_header);
1396                                         break;
1397                                 }
1398                                 /* Check smta in user data field (moov) to be compatible with android */
1399                         case FOURCC('s', 'm', 't', 'a'): {
1400                                         debug_msg(RELEASE, "MPEG4: [smta] SIZE: [%lld]Byte\n", chunk_size);
1401                                         GetSAUTInfoFromSMTATagBox(formatContext, fp, &basic_header);
1402                                         break;
1403                                 }
1404                                 /* Check cdis in user data field (moov) to be compatible with android */
1405                         case FOURCC('c', 'd', 'i', 's'): {
1406                                         debug_msg(RELEASE, "MPEG4: [smta] SIZE: [%lld]Byte\n", chunk_size);
1407                                         GetValueFromCDISTagBox(formatContext, fp, &basic_header);
1408                                         break;
1409                                 }
1410                                 /*/////////////////////////////////////////////////////////////// */
1411                                 /*                  Extracting ID3 Tag Data                    // */
1412                                 /*/////////////////////////////////////////////////////////////// */
1413                         case FOURCC('m', 'e', 't', 'a'): {
1414                                         debug_msg(RELEASE, "MPEG4: [meta] SIZE: [%lld]Byte\n", chunk_size);
1415                                         GetTagFromMetaBox(formatContext, fp, &basic_header);
1416                                         break;
1417                                 }
1418
1419                         case FOURCC('t', 'r', 'a', 'k'): {
1420                                         debug_msg(RELEASE, "MPEG4: [trak] SIZE: [%lld]Byte\n", chunk_size);
1421                                         break;
1422                                 }
1423                         case FOURCC('u', 'u', 'i', 'd'): {
1424                                         unsigned long uuid[4] = {0, };
1425
1426                                         debug_msg(RELEASE, "MPEG4: [uuid] SIZE: [%lld]Byte\n", chunk_size);
1427
1428                                         mmfile_read(fp, (unsigned char *)uuid, sizeof(uuid));
1429
1430                                         if (mmfile_io_be_uint32(uuid[0]) == 0xffcc8263
1431                                                 && mmfile_io_be_uint32(uuid[1]) == 0xf8554a93
1432                                                 && mmfile_io_be_uint32(uuid[2]) == 0x8814587a
1433                                                 && mmfile_io_be_uint32(uuid[3]) == 0x02521fdd) {
1434                                                 char *str = NULL;
1435                                                 str = (char *)malloc(basic_header.size);
1436
1437                                                 if(str != NULL) {
1438                                                         memset(str, 0, basic_header.size);
1439                                                         mmfile_read(fp, (unsigned char *)str, basic_header.size);
1440
1441                                                         if(strstr(str, "<GSpherical:Spherical>true</GSpherical:Spherical>"))
1442                                                                 formatContext->is_360 = 1;
1443                                                         else
1444                                                                 formatContext->is_360 = 0;
1445
1446                                                         if(formatContext->is_360 == 1) {
1447                                                                 if (strstr(str, "<GSpherical:Stitched>true</GSpherical:Stitched>"))
1448                                                                         formatContext->stitched_info = MMFILE_360_STITCHED;
1449                                                                 else
1450                                                                         formatContext->stitched_info = MMFILE_360_NON_STITCHED;
1451                                                         } else {
1452                                                                 formatContext->stitched_info = MMFILE_360_NONE;
1453                                                         }
1454                                                 }
1455                                         }
1456                                         ret = mmfile_seek(fp, basic_header.start_offset + chunk_size, SEEK_SET);
1457
1458                                         break;
1459                                 }
1460                         default: {
1461                                         debug_msg(RELEASE, "4CC: Not Support [%c%c%c%c]. So skip it. Size [%lld Byte]\n",
1462                                                                 ((char *)&basic_header.type)[0], ((char *)&basic_header.type)[1],
1463                                                                 ((char *)&basic_header.type)[2], ((char *)&basic_header.type)[3], chunk_size);
1464                                         ret = mmfile_seek(fp, basic_header.start_offset + chunk_size, SEEK_SET);
1465                                         break;
1466                                 }
1467                 }
1468
1469                 if (ret == MMFILE_UTIL_FAIL) {
1470                         debug_error(DEBUG, "mmfile operation is error\n");
1471                         ret = -1;
1472                         goto exit;
1473                 }
1474
1475                 basic_header.start_offset = mmfile_tell(fp);
1476         }
1477
1478 exit:
1479         mmfile_close(fp);
1480         return ret;
1481 }
1482
1483 static char *get_string(const char *buf, int buf_size, int *bytes_written)
1484 {
1485         int i = 0, c = 0;
1486         char *q = NULL;
1487         char str[512] = {0, };
1488
1489         q = str;
1490         for (i = 0; i < buf_size; i++) {
1491                 c = buf[i];
1492                 if (c == '\0')
1493                         break;
1494                 if ((q - str) >= (int)sizeof(str) - 1)
1495                         break;
1496                 *q++ = c;
1497         }
1498         *q = '\0';
1499
1500         if (strlen(str) > 0) {
1501                 *bytes_written = strlen(str);
1502                 return strdup(str);
1503         } else {
1504                 *bytes_written = 0;
1505                 return NULL;
1506         }
1507 }
1508
1509 static bool is_numeric(const char *buf, int buf_size)
1510 {
1511         int idx = 0;
1512         bool is_num = true;
1513
1514         for (idx = 0; idx < buf_size; idx++) {
1515                 if (isdigit((int)buf[idx])) {
1516                         continue;
1517                 } else {
1518                         is_num = false;
1519                         break;
1520                 }
1521         }
1522
1523         return is_num;
1524 }
1525
1526 char *rtrimN(char *pStr)
1527 {
1528         int pos = 0;
1529         pos = strlen(pStr) - 1;
1530         for (; pos >= 0; pos--) {
1531                 if (pStr[pos] == 0x20) {
1532                         pStr[pos] = 0x00;
1533                 } else {
1534                         break;
1535                 }
1536         }
1537
1538         return strdup(pStr);
1539 }
1540
1541 bool safe_atoi(char *buffer, int *si)
1542
1543 {
1544         char *end;
1545         errno = 0;
1546
1547         const long sl = strtol(buffer, &end, 10);
1548
1549         if (end == buffer) {
1550                 debug_error(RELEASE, "not a decimal number");
1551                 return FALSE;
1552         } else if ('\0' != *end) {
1553                 debug_error(RELEASE, "extra characters at end of input: %s", end);
1554                 return FALSE;
1555         } else if ((LONG_MIN == sl || LONG_MAX == sl) && (ERANGE == errno)) {
1556                 debug_error(RELEASE, "out of range of type long");
1557                 return FALSE;
1558         } else if (sl > INT_MAX) {
1559                 debug_error(RELEASE, "greater than INT_MAX");
1560                 return FALSE;
1561         } else if (sl < INT_MIN) {
1562                 debug_error(RELEASE, "less than INT_MIN");
1563                 return FALSE;
1564         } else {
1565                 *si = (int)sl;
1566         }
1567         return TRUE;
1568 }
1569
1570 static bool make_characterset_array(char ***charset_array)
1571 {
1572         char *locale = MMFileUtilGetLocale(NULL);
1573
1574         *charset_array = calloc(AV_ID3V2_MAX, sizeof(char *));
1575
1576         if (*charset_array == NULL) {
1577                 debug_error(DEBUG, "calloc failed ");
1578                 if (locale != NULL)
1579                         free(locale);
1580                 return false;
1581         }
1582
1583         if (locale != NULL) {
1584                 (*charset_array)[AV_ID3V2_ISO_8859] = strdup(locale);
1585         } else {
1586                 debug_error(DEBUG, "get locale failed");
1587                 (*charset_array)[AV_ID3V2_ISO_8859] = NULL;
1588         }
1589
1590         (*charset_array)[AV_ID3V2_UTF16] = strdup("UCS2");
1591         (*charset_array)[AV_ID3V2_UTF16_BE] = strdup("UTF16-BE");
1592         (*charset_array)[AV_ID3V2_UTF8] = strdup("UTF-8");
1593
1594         return true;
1595 }
1596
1597 static bool release_characterset_array(char **charset_array)
1598 {
1599         int i = 0;
1600
1601         for (i = 0; i < AV_ID3V2_MAX; i++) {
1602                 if (charset_array[i] != NULL) {
1603                         free(charset_array[i]);
1604                         charset_array[i] = NULL;
1605                 }
1606         }
1607
1608         if (charset_array != NULL) {
1609                 free(charset_array);
1610                 charset_array = NULL;
1611         }
1612
1613         return true;
1614 }
1615
1616 static void init_content_info(AvFileContentInfo *pInfo)
1617 {
1618         pInfo->tagV2Info.bTitleMarked = false;
1619         pInfo->tagV2Info.bArtistMarked = false;
1620         pInfo->tagV2Info.bAlbumMarked = false;
1621         pInfo->tagV2Info.bAlbum_ArtistMarked = false;
1622         pInfo->tagV2Info.bYearMarked = false;
1623         pInfo->tagV2Info.bDescriptionMarked = false;
1624         pInfo->tagV2Info.bGenreMarked = false;
1625         pInfo->tagV2Info.bTrackNumMarked = false;
1626         pInfo->tagV2Info.bEncByMarked = false;
1627         pInfo->tagV2Info.bURLMarked = false;
1628         pInfo->tagV2Info.bCopyRightMarked = false;
1629         pInfo->tagV2Info.bOriginArtistMarked = false;
1630         pInfo->tagV2Info.bComposerMarked = false;
1631         pInfo->tagV2Info.bImageMarked = false;
1632
1633         pInfo->tagV2Info.bRecDateMarked = false;
1634         pInfo->tagV2Info.bContentGroupMarked = false;
1635
1636         pInfo->tagV2Info.bUnsyncLyricsMarked = false;
1637         pInfo->tagV2Info.bSyncLyricsMarked = false;
1638         pInfo->tagV2Info.bConductorMarked = false;
1639         pInfo->tagV2Info.bGenreUTF16 = false;
1640
1641         pInfo->imageInfo.bURLInfo = false;
1642         pInfo->imageInfo.pImageBuf = NULL;
1643         pInfo->imageInfo.imageLen = 0;
1644 }
1645
1646 EXPORT_API
1647 bool mm_file_id3tag_parse_v110(AvFileContentInfo *pInfo,  unsigned char *buffer)
1648 {
1649         const char *locale = MMFileUtilGetLocale(NULL);
1650         char *pFullStr = NULL;
1651
1652         debug_msg(RELEASE, "ID3tag v110--------------------------------------------------------------\n");
1653
1654         if (pInfo->tagV2Info.bTitleMarked == false) {
1655                 pFullStr = mmfile_string_convert((const char *)&buffer[3], MP3_ID3_TITLE_LENGTH, "UTF-8", locale, NULL, (unsigned int *)&pInfo->titleLen);
1656                 if (pFullStr != NULL) {
1657                         pInfo->pTitle = rtrimN(pFullStr);
1658                         free(pFullStr);
1659                 }
1660
1661                 debug_msg(RELEASE, "pInfo->pTitle returned =(%s), pInfo->titleLen(%d)\n", pInfo->pTitle, pInfo->titleLen);
1662         }
1663
1664         if (pInfo->tagV2Info.bArtistMarked == false) {
1665                 pFullStr = mmfile_string_convert((const char *)&buffer[33], MP3_ID3_ARTIST_LENGTH, "UTF-8", locale, NULL, (unsigned int *)&pInfo->artistLen);
1666                 if (pFullStr != NULL) {
1667                         pInfo->pArtist = rtrimN(pFullStr);
1668                         free(pFullStr);
1669                 }
1670
1671                 debug_msg(RELEASE, "pInfo->pArtist returned =(%s), pInfo->artistLen(%d)\n", pInfo->pArtist, pInfo->artistLen);
1672         }
1673
1674         if (pInfo->tagV2Info.bAlbumMarked == false) {
1675                 pFullStr = mmfile_string_convert((const char *)&buffer[63], MP3_ID3_ALBUM_LENGTH, "UTF-8", locale, NULL, (unsigned int *)&pInfo->albumLen);
1676                 if (pFullStr != NULL) {
1677                         pInfo->pAlbum = rtrimN(pFullStr);
1678                         free(pFullStr);
1679                 }
1680
1681                 debug_msg(RELEASE, "pInfo->pAlbum returned =(%s), pInfo->albumLen(%d)\n", pInfo->pAlbum, pInfo->albumLen);
1682         }
1683
1684         if (pInfo->tagV2Info.bYearMarked == false) {
1685
1686                 pInfo->pYear = mmfile_string_convert((const char *)&buffer[93], MP3_ID3_YEAR_LENGTH, "UTF-8", locale, NULL, (unsigned int *)&pInfo->yearLen);
1687
1688                 debug_msg(RELEASE, "pInfo->pYear returned =(%s), pInfo->yearLen(%d)\n", pInfo->pYear, pInfo->yearLen);
1689
1690                 if (pInfo->pYear == NULL) {     /*Use same logic with ffmpeg*/
1691                         pInfo->pYear = get_string((const char *)&buffer[93], MP3_ID3_YEAR_LENGTH, (int *)&pInfo->yearLen);
1692                         debug_msg(RELEASE, "pInfo->pYear returned =(%s), pInfo->yearLen(%d)\n", pInfo->pYear, pInfo->yearLen);
1693                 }
1694         }
1695
1696         if (pInfo->tagV2Info.bDescriptionMarked == false) {
1697                 pInfo->pComment = mmfile_string_convert((const char *)&buffer[97], MP3_ID3_DESCRIPTION_LENGTH, "UTF-8", locale, NULL, (unsigned int *)&pInfo->commentLen);
1698                 debug_msg(RELEASE, "pInfo->pComment returned =(%s), pInfo->commentLen(%d)\n", pInfo->pComment, pInfo->commentLen);
1699
1700                 if (pInfo->pComment == NULL) {  /*Use same logic with ffmpeg*/
1701                         pInfo->pComment = get_string((const char *)&buffer[97], MP3_ID3_DESCRIPTION_LENGTH, (int *)&pInfo->commentLen);
1702                         debug_msg(RELEASE, "pInfo->pComment returned =(%s), pInfo->commentLen(%d)\n", pInfo->pComment, pInfo->commentLen);
1703                 }
1704         }
1705
1706         if (pInfo->tagV2Info.bTrackNumMarked == false) {
1707                 pInfo->pTrackNum = mmfile_malloc(5);
1708                 if (pInfo->pTrackNum != NULL) {
1709                         pInfo->pTrackNum[4] = 0;
1710                         snprintf(pInfo->pTrackNum, 4, "%04d", (int)buffer[126]);
1711                         pInfo->tracknumLen = strlen(pInfo->pTrackNum);
1712
1713                         debug_msg(RELEASE, "pInfo->pTrackNum returned =(%s), pInfo->tracknumLen(%d)\n", pInfo->pTrackNum, pInfo->tracknumLen);
1714                 }
1715         }
1716
1717         if (pInfo->tagV2Info.bGenreMarked == false) {
1718                 pInfo->genre = buffer[127];
1719                 debug_msg(RELEASE, "pInfo->genre returned genre number (%d)\n", pInfo->genre);
1720         }
1721
1722         return true;
1723 }
1724
1725 EXPORT_API
1726 bool mm_file_id3tag_parse_v222(AvFileContentInfo *pInfo, unsigned char *buffer)
1727 {
1728         unsigned long taglen = 0;
1729         unsigned long needToloopv2taglen;
1730         unsigned long oneFrameLen = 0;
1731         unsigned long v2numOfFrames = 0;
1732         unsigned long curPos = 0;
1733         char CompTmp[4];
1734         unsigned char *pExtContent = NULL;
1735         unsigned long purelyFramelen = 0;
1736         unsigned int encodingOffSet = 0;
1737         int inx = 0, realCpyFrameNum = 0,
1738             /*checkImgMimeTypeMax = 0, */checkImgExtMax = 0,
1739             imgstartOffset = 0, tmp = 0;
1740
1741         int textEncodingType = 0;
1742
1743         char **charset_array = NULL;
1744
1745         make_characterset_array(&charset_array);
1746
1747         init_content_info(pInfo);
1748
1749         taglen = pInfo->tagV2Info.tagLen;
1750         needToloopv2taglen = taglen - MP3_TAGv2_HEADER_LEN;
1751         curPos = MP3_TAGv2_HEADER_LEN;
1752
1753         debug_msg(RELEASE, "ID3tag v222--------------------------------------------------------------\n");
1754
1755         if (needToloopv2taglen - MP3_TAGv2_22_TXT_HEADER_LEN > MP3_TAGv2_22_TXT_HEADER_LEN) {
1756                 v2numOfFrames = 1;
1757                 while (needToloopv2taglen > MP3_TAGv2_22_TXT_HEADER_LEN) {
1758                         if ((buffer[curPos] < '0' || buffer[curPos] > 'Z') || (buffer[curPos + 1] < '0' || buffer[curPos + 1] > 'Z')
1759                             || (buffer[curPos + 2] < '0' || buffer[curPos + 2] > 'Z'))
1760                                 break;
1761
1762                         memcpy(CompTmp, &buffer[curPos], 3);
1763
1764                         CompTmp[3] = 0;
1765                         oneFrameLen = MP3_TAGv2_22_TXT_HEADER_LEN;
1766                         oneFrameLen += (unsigned long)buffer[3 + curPos] << 16 | (unsigned long)buffer[4 + curPos] << 8
1767                                                 | (unsigned long)buffer[5 + curPos];
1768                         if (oneFrameLen > taglen - curPos)
1769                                 break;
1770                         purelyFramelen = oneFrameLen - MP3_TAGv2_22_TXT_HEADER_LEN;
1771                         curPos += MP3_TAGv2_22_TXT_HEADER_LEN;
1772
1773                         if (oneFrameLen > MP3_TAGv2_22_TXT_HEADER_LEN && purelyFramelen <= taglen - curPos) {
1774                                 curPos += purelyFramelen;
1775
1776                                 if (buffer[curPos - purelyFramelen] == 0x00) {
1777                                         encodingOffSet = 1;
1778                                         textEncodingType = AV_ID3V2_ISO_8859;
1779                                 } else if (buffer[curPos - purelyFramelen] == 0x01) {
1780                                         encodingOffSet = 1;
1781                                         textEncodingType = AV_ID3V2_UTF16;
1782                                 }
1783
1784                                 /*in order to deliver valid string to MP */
1785                                 while ((buffer[curPos - purelyFramelen + encodingOffSet] < 0x20) && (encodingOffSet < purelyFramelen))
1786                                         encodingOffSet++;
1787
1788                                 if (encodingOffSet < purelyFramelen) {
1789                                         realCpyFrameNum = purelyFramelen - encodingOffSet;
1790                                         pExtContent = mmfile_malloc(realCpyFrameNum + 3);
1791
1792                                         if (pExtContent == NULL) {
1793                                                 debug_error(DEBUG, "out of memory for pExtContent\n");
1794                                                 continue;
1795                                         }
1796
1797                                         memset(pExtContent, '\0', realCpyFrameNum + 3);
1798
1799                                         memcpy(pExtContent, &buffer[curPos - purelyFramelen + encodingOffSet], purelyFramelen - encodingOffSet);
1800
1801                                         if (realCpyFrameNum > 0) {
1802                                                 if (strncmp((char *)CompTmp, "TT2", 3) == 0 && pInfo->tagV2Info.bTitleMarked == false) {
1803                                                         pInfo->pTitle = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->titleLen);
1804                                                         debug_msg(RELEASE, "pInfo->pTitle returned = (%s), pInfo->titleLen(%d)\n", pInfo->pTitle, pInfo->titleLen);
1805                                                         pInfo->tagV2Info.bTitleMarked = true;
1806                                                 } else if (strncmp((char *)CompTmp, "TP1", 3) == 0 && pInfo->tagV2Info.bArtistMarked == false) {
1807                                                         pInfo->pArtist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->artistLen);
1808                                                         debug_msg(RELEASE, "pInfo->pArtist returned = (%s), pInfo->artistLen(%d)\n", pInfo->pArtist, pInfo->artistLen);
1809                                                         pInfo->tagV2Info.bArtistMarked = true;
1810                                                 } else if (strncmp((char *)CompTmp, "TP2", 3) == 0 && pInfo->tagV2Info.bAlbum_ArtistMarked == false) {
1811                                                         pInfo->pAlbum_Artist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->album_artistLen);
1812                                                         debug_msg(RELEASE, "pInfo->pAlbum_Artist returned = (%s), pInfo->album_artistLen(%d)\n", pInfo->pAlbum_Artist, pInfo->album_artistLen);
1813                                                         pInfo->tagV2Info.bAlbum_ArtistMarked = true;
1814                                                 } else if (strncmp((char *)CompTmp, "TP3", 3) == 0 && pInfo->tagV2Info.bConductorMarked == false) {
1815                                                         pInfo->pConductor = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->conductorLen);
1816                                                         debug_msg(RELEASE, "pInfo->pConductor returned = (%s), pInfo->conductorLen(%d)\n", pInfo->pConductor, pInfo->conductorLen);
1817                                                         pInfo->tagV2Info.bConductorMarked = true;
1818                                                 } else if (strncmp((char *)CompTmp, "TAL", 3) == 0 && pInfo->tagV2Info.bAlbumMarked == false) {
1819                                                         pInfo->pAlbum = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->albumLen);
1820                                                         debug_msg(RELEASE, "pInfo->pAlbum returned = (%s), pInfo->albumLen(%d)\n", pInfo->pAlbum, pInfo->albumLen);
1821                                                         pInfo->tagV2Info.bAlbumMarked = true;
1822                                                 } else if (strncmp((char *)CompTmp, "TYE", 3) == 0 && pInfo->tagV2Info.bYearMarked == false) {
1823                                                         pInfo->pYear = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->yearLen);
1824                                                         debug_msg(RELEASE, "pInfo->pYear returned = (%s), pInfo->yearLen(%d)\n", pInfo->pYear, pInfo->yearLen);
1825                                                         pInfo->tagV2Info.bYearMarked = true;
1826                                                 } else if (strncmp((char *)CompTmp, "COM", 3) == 0 && pInfo->tagV2Info.bDescriptionMarked == false) {
1827                                                         /*skip language data! */
1828                                                         if (realCpyFrameNum > 4) {
1829                                                                 realCpyFrameNum -= 4;
1830                                                                 tmp = 4;
1831
1832                                                                 /*pExtContent[tmp+1] value should't have encoding value */
1833                                                                 if (pExtContent[tmp] > 0x20 && (pExtContent[tmp - 1] == 0x00 || pExtContent[tmp - 1] == 0x01)) {
1834                                                                         if (pExtContent[tmp - 1] == 0x00)
1835                                                                                 textEncodingType = AV_ID3V2_ISO_8859;
1836                                                                         else
1837                                                                                 textEncodingType = AV_ID3V2_UTF16;
1838
1839                                                                         pInfo->pComment = mmfile_string_convert((char *)&pExtContent[tmp], realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->commentLen);
1840                                                                         debug_msg(RELEASE, "pInfo->pComment returned = (%s), pInfo->commentLen(%d)\n", pInfo->pComment, pInfo->commentLen);
1841                                                                         pInfo->tagV2Info.bDescriptionMarked = true;
1842                                                                 } else {
1843                                                                         debug_msg(RELEASE, "mmf_file_id3tag_parse_v222: failed to get Comment Info tmp(%d), purelyFramelen - encodingOffSet(%lu)\n", tmp, purelyFramelen - encodingOffSet);
1844                                                                 }
1845                                                         } else {
1846                                                                 debug_msg(RELEASE, "mmf_file_id3tag_parse_v222: Description info too small to parse realCpyFrameNum(%d)\n", realCpyFrameNum);
1847                                                         }
1848                                                         tmp = 0;
1849
1850                                                 } else if (strncmp((char *)CompTmp, "TCO", 3) == 0 && pInfo->tagV2Info.bGenreMarked == false) {
1851                                                         pInfo->pGenre = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->genreLen);
1852                                                         debug_msg(RELEASE, "pInfo->pGenre returned = (%s), pInfo->genreLen(%d)\n", pInfo->pGenre, pInfo->genreLen);
1853
1854                                                         if ((pInfo->pGenre != NULL) && (pInfo->genreLen > 0)) {
1855                                                                 bool ret = FALSE;
1856                                                                 int int_genre = -1;
1857
1858                                                                 ret = is_numeric(pInfo->pGenre, pInfo->genreLen);
1859
1860                                                                 if (ret == TRUE) {
1861                                                                         ret = safe_atoi(pInfo->pGenre, &int_genre);
1862                                                                         if (ret == TRUE) {
1863                                                                                 debug_msg(RELEASE, "genre information is inteager [%d]\n", int_genre);
1864
1865                                                                                 /*Change int to string */
1866                                                                                 if ((0 <= int_genre) && (int_genre < GENRE_COUNT - 1)) {
1867                                                                                         /*save genreinfo like "(123)". mm_file_id3tag_restore_content_info convert it to string*/
1868                                                                                         char tmp_genre[6] = {0, };      /*ex. "(123)+NULL"*/
1869                                                                                         int tmp_genre_len = 0;
1870
1871                                                                                         memset(tmp_genre, 0, 6);
1872                                                                                         snprintf(tmp_genre, sizeof(tmp_genre), "(%d)", int_genre);
1873
1874                                                                                         tmp_genre_len = strlen(tmp_genre);
1875                                                                                         if (tmp_genre_len > 0) {
1876                                                                                                 if (pInfo->pGenre) _FREE_EX(pInfo->pGenre);
1877                                                                                                 pInfo->pGenre = mmfile_malloc(sizeof(char) * (tmp_genre_len + 1));
1878                                                                                                 if (pInfo->pGenre) {
1879                                                                                                         strncpy(pInfo->pGenre, tmp_genre, tmp_genre_len);
1880                                                                                                         pInfo->pGenre[tmp_genre_len] = 0;
1881                                                                                                 }
1882                                                                                         }
1883                                                                                 }
1884                                                                         } else {
1885                                                                                 debug_error(RELEASE, "genre information is wrong inteager [%s]\n", pInfo->pGenre);
1886                                                                         }
1887                                                                 }
1888                                                         }
1889
1890                                                         pInfo->tagV2Info.bGenreMarked = true;
1891                                                 } else if (strncmp((char *)CompTmp, "TRK", 3) == 0 && pInfo->tagV2Info.bTrackNumMarked == false) {
1892                                                         pInfo->pTrackNum = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->tracknumLen);
1893                                                         debug_msg(RELEASE, "pInfo->pTrackNum returned = (%s), pInfo->tracknumLen(%d)\n", pInfo->pTrackNum, pInfo->tracknumLen);
1894                                                         pInfo->tagV2Info.bTrackNumMarked = true;
1895                                                 } else if (strncmp((char *)CompTmp, "TEN", 3) == 0 && pInfo->tagV2Info.bEncByMarked == false) {
1896                                                         pInfo->pEncBy = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->encbyLen);
1897                                                         debug_msg(RELEASE, "pInfo->pEncBy returned = (%s), pInfo->encbyLen(%d)\n", pInfo->pEncBy, pInfo->encbyLen);
1898                                                         pInfo->tagV2Info.bEncByMarked = true;
1899                                                 } else if (strncmp((char *)CompTmp, "WXX", 3) == 0 && pInfo->tagV2Info.bURLMarked == false) {
1900                                                         if (realCpyFrameNum > 4) {
1901                                                                 /*skip language data! */
1902                                                                 realCpyFrameNum -= 4;
1903                                                                 tmp = 4;
1904
1905                                                                 /*pExtContent[tmp+1] value should't have null value */
1906                                                                 if (pExtContent[tmp] > 0x20 && (pExtContent[tmp - 1] == 0x00 || pExtContent[tmp - 1] == 0x01)) {
1907                                                                         if (pExtContent[tmp - 1] == 0x00)
1908                                                                                 textEncodingType = AV_ID3V2_ISO_8859;
1909                                                                         else
1910                                                                                 textEncodingType = AV_ID3V2_UTF16;
1911
1912                                                                         pInfo->pURL = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->urlLen);
1913                                                                         debug_msg(RELEASE, "pInfo->pURL returned = (%s), pInfo->urlLen(%d)\n", pInfo->pURL, pInfo->urlLen);
1914                                                                         pInfo->tagV2Info.bURLMarked = true;
1915                                                                 } else {
1916                                                                         debug_msg(RELEASE, "mmf_file_id3tag_parse_v222: failed to get URL Info tmp(%d), purelyFramelen - encodingOffSet(%lu)\n", tmp, purelyFramelen - encodingOffSet);
1917                                                                 }
1918                                                         } else {
1919                                                                 debug_msg(RELEASE, "mmf_file_id3tag_parse_v222: URL info too small to parse realCpyFrameNum(%d)\n", realCpyFrameNum);
1920                                                         }
1921                                                         tmp = 0;
1922                                                 } else if (strncmp((char *)CompTmp, "TCR", 3) == 0 && pInfo->tagV2Info.bCopyRightMarked == false) {
1923                                                         pInfo->pCopyright = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->copyrightLen);
1924                                                         debug_msg(RELEASE, "pInfo->pCopyright returned = (%s), pInfo->copyrightLen(%d)\n", pInfo->pCopyright, pInfo->copyrightLen);
1925                                                         pInfo->tagV2Info.bCopyRightMarked = true;
1926                                                 } else if (strncmp((char *)CompTmp, "TOA", 3) == 0 && pInfo->tagV2Info.bOriginArtistMarked == false) {
1927                                                         pInfo->pOriginArtist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->originartistLen);
1928                                                         debug_msg(RELEASE, "pInfo->pOriginArtist returned = (%s), pInfo->originartistLen(%d)\n", pInfo->pOriginArtist, pInfo->originartistLen);
1929                                                         pInfo->tagV2Info.bOriginArtistMarked = true;
1930                                                 } else if (strncmp((char *)CompTmp, "TCM", 3) == 0 && pInfo->tagV2Info.bComposerMarked == false) {
1931                                                         pInfo->pComposer = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->composerLen);
1932                                                         debug_msg(RELEASE, "pInfo->pComposer returned = (%s), pInfo->originartistLen(%d)\n", pInfo->pComposer, pInfo->composerLen);
1933                                                         pInfo->tagV2Info.bComposerMarked = true;
1934                                                 } else if (strncmp((char *)CompTmp, "TRD", 3) == 0 && pInfo->tagV2Info.bRecDateMarked == false) {
1935                                                         pInfo->pRecDate = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->recdateLen);
1936                                                         debug_msg(RELEASE, "pInfo->pRecDate returned = (%s), pInfo->recdateLen(%d)\n", pInfo->pRecDate, pInfo->recdateLen);
1937                                                         pInfo->tagV2Info.bRecDateMarked = true;
1938                                                 } else if (strncmp((char *)CompTmp, "PIC", 3) == 0 && pInfo->tagV2Info.bImageMarked == false && realCpyFrameNum <= 2000000) {
1939                                                         if (pExtContent[0] != 0) {
1940                                                                 for (inx = 0; inx < MP3_ID3_IMAGE_EXT_MAX_LENGTH; inx++)
1941                                                                         pInfo->imageInfo.imageExt[inx] = '\0';/*ini mimetype variable */
1942
1943                                                                 while ((checkImgExtMax < MP3_ID3_IMAGE_EXT_MAX_LENGTH - 1) && pExtContent[checkImgExtMax] != '\0') {
1944                                                                         pInfo->imageInfo.imageExt[checkImgExtMax] = pExtContent[checkImgExtMax];
1945                                                                         checkImgExtMax++;
1946                                                                 }
1947                                                         } else {
1948                                                                 debug_msg(RELEASE, "mmf_file_id3tag_parse_v222: PIC image's not included to image Extention\n");
1949                                                         }
1950
1951                                                         imgstartOffset += checkImgExtMax;
1952
1953                                                         if (pExtContent[imgstartOffset] < AV_ID3V2_PICTURE_TYPE_MAX) {
1954                                                                 pInfo->imageInfo.pictureType = pExtContent[imgstartOffset];
1955                                                         }
1956                                                         imgstartOffset++;/*PictureType(1byte) */
1957
1958                                                         if (pExtContent[imgstartOffset] != 0x0) {
1959                                                                 int cur_pos = 0;
1960                                                                 int dis_len = 0;
1961                                                                 int new_dis_len = 0;
1962                                                                 char *tmp_desc = NULL;
1963
1964                                                                 while (1) {
1965                                                                         if (pExtContent[imgstartOffset + cur_pos] == '\0') {
1966                                                                                 if (realCpyFrameNum < imgstartOffset + cur_pos) {
1967                                                                                         debug_error(DEBUG, "End of APIC Tag %d %d %d\n", realCpyFrameNum, imgstartOffset, cur_pos);
1968                                                                                         break;
1969                                                                                 }
1970                                                                                 /*check end of image description*/
1971                                                                                 if ((pExtContent[imgstartOffset + cur_pos + 1] == gTagJPEGHeader[0]) ||
1972                                                                                     (pExtContent[imgstartOffset + cur_pos + 1] == gTagPNGHeader[0])) {
1973                                                                                         debug_msg(RELEASE, "length of description (%d)", cur_pos);
1974                                                                                         break;
1975                                                                                 }
1976                                                                         }
1977                                                                         cur_pos++;
1978                                                                 }
1979
1980                                                                 dis_len = cur_pos + 1;
1981
1982                                                                 tmp_desc = mmfile_malloc(sizeof(char) * dis_len);
1983
1984                                                                 if (tmp_desc != NULL) {
1985                                                                         memcpy(tmp_desc, pExtContent + imgstartOffset, dis_len);
1986
1987                                                                         /*convert description*/
1988                                                                         pInfo->imageInfo.imageDescription = mmfile_string_convert(tmp_desc, dis_len, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&new_dis_len);
1989                                                                         mmfile_free(tmp_desc);
1990                                                                         debug_msg(RELEASE, "new_desc %s(%d)\n", pInfo->imageInfo.imageDescription, new_dis_len);
1991                                                                         pInfo->imageInfo.imgDesLen = new_dis_len; /**/
1992                                                                 }
1993
1994                                                                 imgstartOffset += cur_pos;
1995                                                         } else {
1996                                                                 pInfo->imageInfo.imgDesLen = 0;
1997                                                         }
1998
1999                                                         if ((pExtContent[imgstartOffset] == '\0') && (realCpyFrameNum - imgstartOffset > 0)) {
2000                                                                 imgstartOffset++; /* endofDesceriptionType(1byte) */
2001
2002                                                                 while (pExtContent[imgstartOffset] == '\0') {   /*some content has useless '\0' in front of picture data */
2003                                                                         imgstartOffset++;
2004                                                                 }
2005
2006                                                                 debug_msg(RELEASE, "after scaning imgDescription imgstartOffset(%d) value!\n", imgstartOffset);
2007
2008                                                                 if (realCpyFrameNum - imgstartOffset > 0) {
2009                                                                         pInfo->imageInfo.imageLen = realCpyFrameNum - imgstartOffset;
2010                                                                         pInfo->imageInfo.pImageBuf = mmfile_malloc(pInfo->imageInfo.imageLen + 1);
2011
2012                                                                         if (pInfo->imageInfo.pImageBuf != NULL) {
2013                                                                                 memcpy(pInfo->imageInfo.pImageBuf, pExtContent + imgstartOffset, pInfo->imageInfo.imageLen);
2014                                                                                 pInfo->imageInfo.pImageBuf[pInfo->imageInfo.imageLen] = 0;
2015                                                                         }
2016
2017                                                                         if (IS_INCLUDE_URL(pInfo->imageInfo.imageMIMEType))
2018                                                                                 pInfo->imageInfo.bURLInfo = true; /*if mimetype is "-->", image date has an URL */
2019                                                                 } else {
2020                                                                         debug_msg(RELEASE, "No APIC image!! realCpyFrameNum(%d) - imgstartOffset(%d)\n", realCpyFrameNum, imgstartOffset);
2021                                                                 }
2022                                                         }
2023
2024                                                         /*checkImgMimeTypeMax = 0;*/
2025                                                         checkImgExtMax = 0;
2026                                                         inx = 0;
2027                                                         imgstartOffset = 0;
2028                                                         pInfo->tagV2Info.bImageMarked = true;
2029
2030                                                 }
2031                                         }
2032
2033                                 }
2034                         } else {
2035                                 curPos += purelyFramelen;
2036                                 if (purelyFramelen != 0)
2037                                         needToloopv2taglen = MP3_TAGv2_22_TXT_HEADER_LEN;
2038                         }
2039
2040                         if (pExtContent)        _FREE_EX(pExtContent);
2041                         memset(CompTmp, 0, 4);
2042                         if (curPos < taglen) {
2043                                 needToloopv2taglen -= oneFrameLen;
2044                                 v2numOfFrames++;
2045                         } else
2046                                 needToloopv2taglen = MP3_TAGv2_22_TXT_HEADER_LEN;
2047                         oneFrameLen = 0;
2048                         encodingOffSet = 0;
2049                         realCpyFrameNum = 0;
2050                         textEncodingType = 0;
2051                         purelyFramelen = 0;
2052
2053                 }
2054         }
2055
2056         release_characterset_array(charset_array);
2057
2058         if (taglen) {
2059                 return true;
2060         } else {
2061                 return false;
2062         }
2063 }
2064
2065 EXPORT_API
2066 bool mm_file_id3tag_parse_v223(AvFileContentInfo *pInfo, unsigned char *buffer)
2067 {
2068         unsigned long taglen = 0;
2069         unsigned long needToloopv2taglen;
2070         unsigned long oneFrameLen = 0;
2071         unsigned long v2numOfFrames = 0;
2072         unsigned long curPos = 0;
2073         char CompTmp[5];
2074         unsigned char *pExtContent = NULL;
2075         unsigned long purelyFramelen = 0;
2076         unsigned int encodingOffSet = 0;
2077         int inx = 0, realCpyFrameNum = 0, checkImgMimeTypeMax = 0, imgstartOffset = 0,  tmp = 0;
2078         int textEncodingType = 0;
2079         char **charset_array = NULL;
2080         const char *MIME_PRFIX = "image/";
2081
2082         make_characterset_array(&charset_array);
2083
2084         init_content_info(pInfo);
2085
2086         taglen = pInfo->tagV2Info.tagLen;
2087         needToloopv2taglen = taglen - MP3_TAGv2_HEADER_LEN;
2088         curPos = MP3_TAGv2_HEADER_LEN;
2089
2090         debug_msg(RELEASE, "ID3tag v223--------------------------------------------------------------\n");
2091
2092         /* check Extended Header */
2093         if (buffer[5] & 0x40) {
2094                 /* if extended header exists, skip it*/
2095                 int extendedHeaderLen = (unsigned long)buffer[10] << 21 | (unsigned long)buffer[11] << 14 | (unsigned long)buffer[12] << 7  | (unsigned long)buffer[13];
2096
2097                 debug_msg(RELEASE, "--------------- extendedHeaderLen = %d\n", extendedHeaderLen);
2098
2099                 if (extendedHeaderLen > (int)(taglen - curPos)) {
2100                         debug_error(DEBUG, "extended header too long.\n");
2101                 } else {
2102                         curPos += extendedHeaderLen;
2103                         curPos += 4;
2104                 }
2105         }
2106
2107         if (needToloopv2taglen - MP3_TAGv2_23_TXT_HEADER_LEN > MP3_TAGv2_23_TXT_HEADER_LEN) {
2108                 v2numOfFrames = 1;
2109                 while (needToloopv2taglen > MP3_TAGv2_23_TXT_HEADER_LEN) {
2110                         if ((buffer[curPos] < '0' || buffer[curPos] > 'Z') || (buffer[curPos + 1] < '0' || buffer[curPos + 1] > 'Z')
2111                             || (buffer[curPos + 2] < '0' || buffer[curPos + 2] > 'Z') || (buffer[curPos + 3] < '0' || buffer[curPos + 3] > 'Z'))
2112                                 break;
2113
2114                         memcpy(CompTmp, &buffer[curPos], 4);
2115
2116                         CompTmp[4] = 0;
2117                         oneFrameLen = MP3_TAGv2_23_TXT_HEADER_LEN;
2118                         oneFrameLen += (unsigned long)buffer[4 + curPos] << 24 | (unsigned long)buffer[5 + curPos] << 16
2119                                                 | (unsigned long)buffer[6 + curPos] << 8 | (unsigned long)buffer[7 + curPos];
2120
2121                         debug_msg(RELEASE, "----------------------------------------------------------------------------------------------------\n");
2122
2123                         if (oneFrameLen > taglen - curPos)
2124                                 break;
2125
2126                         purelyFramelen = oneFrameLen - MP3_TAGv2_23_TXT_HEADER_LEN;
2127                         curPos += MP3_TAGv2_23_TXT_HEADER_LEN;
2128
2129                         if (oneFrameLen > MP3_TAGv2_23_TXT_HEADER_LEN && purelyFramelen <= taglen - curPos) {
2130                                 curPos += purelyFramelen;
2131
2132                                 if (IS_ENCODEDBY_UTF16(buffer + (curPos - purelyFramelen))) {
2133                                         encodingOffSet = 2;
2134                                         debug_msg(RELEASE, "this text string(%s) encoded by UTF16 encodingOffSet(%d)\n", CompTmp, encodingOffSet);
2135                                         textEncodingType = AV_ID3V2_UTF16;
2136                                 } else if (IS_ENCODEDBY_UTF16_R(buffer + (curPos - purelyFramelen))) {
2137                                         encodingOffSet = 2;
2138                                         debug_msg(RELEASE, "this text string(%s) encoded by UTF16 encodingOffSet(%d)\n", CompTmp, encodingOffSet);
2139                                         textEncodingType = AV_ID3V2_UTF16_BE;
2140                                 } else if (IS_ENCODEDBY_UTF16(buffer + (curPos - purelyFramelen + 1))) {
2141                                         encodingOffSet = 3;
2142                                         debug_msg(RELEASE, "this text string(%s) encoded by UTF16 encodingOffSet(%d)\n", CompTmp, encodingOffSet);
2143                                         textEncodingType = AV_ID3V2_UTF16;
2144                                 } else if (IS_ENCODEDBY_UTF16_R(buffer + (curPos - purelyFramelen + 1))) {
2145                                         encodingOffSet = 3;
2146                                         debug_msg(RELEASE, "this text string(%s) encoded by UTF16 encodingOffSet(%d)\n", CompTmp, encodingOffSet);
2147                                         textEncodingType = AV_ID3V2_UTF16_BE;
2148                                 } else {
2149                                         if (buffer[curPos - purelyFramelen + encodingOffSet] == 0x00) {
2150                                                 debug_msg(RELEASE, "encodingOffset will be set to 1\n");
2151                                                 encodingOffSet = 1;
2152                                         } else {
2153                                                 debug_msg(RELEASE, "Finding encodingOffset\n");
2154
2155                                                 while ((buffer[curPos - purelyFramelen + encodingOffSet] < 0x20) && (encodingOffSet < purelyFramelen)) /* text string encoded by ISO-8859-1 */
2156                                                         encodingOffSet++;
2157                                         }
2158                                         textEncodingType = AV_ID3V2_ISO_8859;
2159                                         debug_msg(RELEASE, "this text string(%s) encoded by ISO-8859-1 encodingOffSet(%d)\n", CompTmp, encodingOffSet);
2160                                 }
2161
2162                                 if (encodingOffSet < purelyFramelen) {
2163                                         realCpyFrameNum = purelyFramelen - encodingOffSet;
2164                                         pExtContent = mmfile_malloc(realCpyFrameNum + 3);
2165
2166                                         if (pExtContent == NULL) {
2167                                                 debug_msg(DEBUG, "pExtContent malloc failed\n");
2168                                                 continue;
2169                                         }
2170
2171                                         memset(pExtContent, '\0', realCpyFrameNum + 3);
2172
2173                                         if (textEncodingType != AV_ID3V2_UTF16 && textEncodingType != AV_ID3V2_UTF16_BE) {
2174                                                 if (CompTmp[0] == 'T' || (strcmp(CompTmp, "APIC") == 0)) {
2175                                                         debug_msg(RELEASE, "get the new text ecoding type\n");
2176                                                         textEncodingType = buffer[curPos - purelyFramelen + encodingOffSet - 1];
2177                                                 }
2178                                         }
2179
2180                                         if (textEncodingType > AV_ID3V2_MAX) {
2181                                                 debug_msg(DEBUG, "WRONG ENCOIDNG TYPE [%d], FRAME[%s]\n", textEncodingType, (char *)CompTmp);
2182                                                 continue;
2183                                         }
2184
2185                                         memcpy(pExtContent, &buffer[curPos - purelyFramelen + encodingOffSet], purelyFramelen - encodingOffSet);
2186                                         if (realCpyFrameNum > 0) {
2187                                                 if (strncmp((char *)CompTmp, "TIT2", 4) == 0 && pInfo->tagV2Info.bTitleMarked == false) {
2188                                                         pInfo->pTitle = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->titleLen);
2189                                                         debug_msg(RELEASE, "pInfo->pTitle returned = (%s), pInfo->titleLen(%d)\n", pInfo->pTitle, pInfo->titleLen);
2190                                                         pInfo->tagV2Info.bTitleMarked = true;
2191
2192                                                 } else if (strncmp((char *)CompTmp, "TPE1", 4) == 0 && pInfo->tagV2Info.bArtistMarked == false) {
2193                                                         pInfo->pArtist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->artistLen);
2194                                                         debug_msg(RELEASE, "pInfo->pArtist returned = (%s), pInfo->artistLen(%d)\n", pInfo->pArtist, pInfo->artistLen);
2195                                                         pInfo->tagV2Info.bArtistMarked = true;
2196                                                 } else if (strncmp((char *)CompTmp, "TPE2", 4) == 0 && pInfo->tagV2Info.bAlbum_ArtistMarked == false) {
2197                                                         pInfo->pAlbum_Artist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->album_artistLen);
2198                                                         debug_msg(RELEASE, "pInfo->pAlbum_Artist returned = (%s), pInfo->album_artistLen(%d)\n", pInfo->pAlbum_Artist, pInfo->album_artistLen);
2199                                                         pInfo->tagV2Info.bAlbum_ArtistMarked = true;
2200                                                 } else if (strncmp((char *)CompTmp, "TPE3", 4) == 0 && pInfo->tagV2Info.bConductorMarked == false) {
2201                                                         pInfo->pConductor = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->conductorLen);
2202                                                         debug_msg(RELEASE, "pInfo->pConductor returned = (%s), pInfo->conductorLen(%d)\n", pInfo->pConductor, pInfo->conductorLen);
2203                                                         pInfo->tagV2Info.bConductorMarked = true;
2204                                                 } else if (strncmp((char *)CompTmp, "TALB", 4) == 0 && pInfo->tagV2Info.bAlbumMarked == false) {
2205                                                         pInfo->pAlbum = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->albumLen);
2206                                                         debug_msg(RELEASE, "pInfo->pAlbum returned = (%s), pInfo->albumLen(%d)\n", pInfo->pAlbum, pInfo->albumLen);
2207                                                         pInfo->tagV2Info.bAlbumMarked = true;
2208                                                 } else if (strncmp((char *)CompTmp, "TYER", 4) == 0 && pInfo->tagV2Info.bYearMarked == false) {
2209                                                         pInfo->pYear = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->yearLen);
2210                                                         debug_msg(RELEASE, "pInfo->pYear returned = (%s), pInfo->yearLen(%d)\n", pInfo->pYear, pInfo->yearLen);
2211                                                         pInfo->tagV2Info.bYearMarked = true;
2212                                                 } else if (strncmp((char *)CompTmp, "COMM", 4) == 0 && pInfo->tagV2Info.bDescriptionMarked == false) {
2213                                                         if (realCpyFrameNum > 3) {
2214                                                                 realCpyFrameNum -= 3;
2215                                                                 tmp = 3;
2216
2217                                                                 /*pExtContent[tmp+1] value should't have encoding value */
2218                                                                 if (pExtContent[tmp] == 0x00 || pExtContent[tmp] == 0xFF || pExtContent[tmp] == 0xFE) {
2219                                                                         if ((IS_ENCODEDBY_UTF16(pExtContent + tmp) || IS_ENCODEDBY_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 2) {
2220                                                                                 while ((NEWLINE_OF_UTF16(pExtContent + tmp) || NEWLINE_OF_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 4) {
2221                                                                                         realCpyFrameNum -= 4;
2222                                                                                         tmp += 4;
2223                                                                                 }
2224
2225                                                                                 if (IS_ENCODEDBY_UTF16(pExtContent + tmp) && (realCpyFrameNum > 2)) {
2226                                                                                         realCpyFrameNum -= 2;
2227                                                                                         tmp += 2;
2228                                                                                         textEncodingType = AV_ID3V2_UTF16;
2229                                                                                 } else if (IS_ENCODEDBY_UTF16_R(pExtContent + tmp) && (realCpyFrameNum > 2)) {
2230                                                                                         realCpyFrameNum -= 2;
2231                                                                                         tmp += 2;
2232                                                                                         textEncodingType = AV_ID3V2_UTF16_BE;
2233                                                                                 } else if (IS_ENCODEDBY_UTF16(pExtContent + tmp + 1) && (realCpyFrameNum > 3)) {
2234                                                                                         realCpyFrameNum -= 3;
2235                                                                                         tmp += 3;
2236                                                                                         textEncodingType = AV_ID3V2_UTF16;
2237                                                                                 } else if (IS_ENCODEDBY_UTF16_R(pExtContent + tmp + 1)  && (realCpyFrameNum > 3)) {
2238                                                                                         realCpyFrameNum -= 3;
2239                                                                                         tmp += 3;
2240                                                                                         textEncodingType = AV_ID3V2_UTF16_BE;
2241                                                                                 } else {
2242                                                                                         debug_msg(RELEASE, "pInfo->pComment Never Get Here!!\n");
2243                                                                                 }
2244                                                                         } else {
2245                                                                                 while ((pExtContent[tmp] < 0x20) && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
2246                                                                                         realCpyFrameNum--;
2247                                                                                         tmp++;
2248                                                                                 }
2249                                                                                 textEncodingType = AV_ID3V2_ISO_8859;
2250                                                                         }
2251
2252                                                                         debug_msg(RELEASE, "tmp(%d) textEncodingType(%d), realCpyFrameNum(%d)\n", tmp, textEncodingType, realCpyFrameNum);
2253                                                                         pInfo->pComment = mmfile_string_convert((const char *)&pExtContent[tmp], realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->commentLen);
2254                                                                 } else {
2255                                                                         debug_msg(RELEASE, "failed to get Comment Info tmp(%d), purelyFramelen - encodingOffSet(%lu)\n", tmp, purelyFramelen - encodingOffSet);
2256                                                                         pInfo->commentLen = 0;
2257                                                                 }
2258                                                         } else {
2259                                                                 debug_msg(RELEASE, "Description info too small to parse realCpyFrameNum(%d)\n", realCpyFrameNum);
2260                                                                 pInfo->commentLen = 0;
2261                                                         }
2262                                                         tmp = 0;
2263
2264                                                         debug_msg(RELEASE, "pInfo->pComment returned = (%s), pInfo->commentLen(%d)\n", pInfo->pComment, pInfo->commentLen);
2265                                                         pInfo->tagV2Info.bDescriptionMarked = true;
2266                                                 } else if (strncmp((char *)CompTmp, "SYLT", 4) == 0 && pInfo->tagV2Info.bSyncLyricsMarked == false) {
2267                                                         int idx = 0;
2268                                                         int copy_len = 0;
2269                                                         int copy_start_pos = tmp;
2270                                                         AvSynclyricsInfo *synclyrics_info = NULL;
2271                                                         GList *synclyrics_info_list = NULL;
2272
2273                                                         if (realCpyFrameNum > 5) {
2274                                                                 realCpyFrameNum -= 5;
2275                                                                 tmp = 5;
2276
2277                                                                 /*pExtContent[tmp+1] value should't have encoding value */
2278                                                                 if (pExtContent[tmp] == 0x00 || pExtContent[tmp] == 0xFF || pExtContent[tmp] == 0xFE) {
2279                                                                         if ((IS_ENCODEDBY_UTF16(pExtContent + tmp) || IS_ENCODEDBY_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 2) {
2280                                                                                 while ((NEWLINE_OF_UTF16(pExtContent + tmp) || NEWLINE_OF_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 4) {
2281                                                                                         realCpyFrameNum -= 4;
2282                                                                                         tmp += 4;
2283                                                                                 }
2284
2285                                                                                 if (IS_ENCODEDBY_UTF16(pExtContent + tmp) && (realCpyFrameNum > 2)) {
2286                                                                                         realCpyFrameNum -= 2;
2287                                                                                         tmp += 2;
2288                                                                                         textEncodingType = AV_ID3V2_UTF16;
2289                                                                                 } else if (IS_ENCODEDBY_UTF16_R(pExtContent + tmp) && (realCpyFrameNum > 2)) {
2290                                                                                         realCpyFrameNum -= 2;
2291                                                                                         tmp += 2;
2292                                                                                         textEncodingType = AV_ID3V2_UTF16_BE;
2293                                                                                 } else if (IS_ENCODEDBY_UTF16(pExtContent + tmp + 1) && (realCpyFrameNum > 3)) {
2294                                                                                         realCpyFrameNum -= 3;
2295                                                                                         tmp += 3;
2296                                                                                         textEncodingType = AV_ID3V2_UTF16;
2297                                                                                 } else if (IS_ENCODEDBY_UTF16_R(pExtContent + tmp + 1)  && (realCpyFrameNum > 3)) {
2298                                                                                         realCpyFrameNum -= 3;
2299                                                                                         tmp += 3;
2300                                                                                         textEncodingType = AV_ID3V2_UTF16_BE;
2301                                                                                 } else {
2302                                                                                         debug_msg(RELEASE, "pInfo->pSyncLyrics Never Get Here!!\n");
2303                                                                                 }
2304                                                                         } else {
2305                                                                                 while ((pExtContent[tmp] < 0x20) && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
2306                                                                                         realCpyFrameNum--;
2307                                                                                         tmp++;
2308                                                                                 }
2309                                                                                 textEncodingType = AV_ID3V2_ISO_8859;
2310                                                                         }
2311
2312                                                                         debug_msg(RELEASE, "tmp(%d) textEncodingType(%d), realCpyFrameNum(%d)\n", tmp, textEncodingType, realCpyFrameNum);
2313
2314                                                                         if (realCpyFrameNum < MMFILE_SYNC_LYRIC_INFO_MIN_LEN) {
2315                                                                                 debug_msg(RELEASE, "failed to get Synchronised lyrics Info realCpyFramNum(%d)\n", realCpyFrameNum);
2316                                                                                 pInfo->syncLyricsNum = 0;
2317                                                                         } else {
2318                                                                                 if (textEncodingType == AV_ID3V2_UTF16) {
2319                                                                                         debug_warning(DEBUG, "[AV_ID3V2_UTF16] not implemented\n");
2320                                                                                 } else if (textEncodingType == AV_ID3V2_UTF16_BE) {
2321                                                                                         debug_warning(DEBUG, "[AV_ID3V2_UTF16_BE] not implemented\n");
2322                                                                                 } else {
2323                                                                                         for (idx = 0; idx < realCpyFrameNum; idx++) {
2324                                                                                                 if (pExtContent[tmp + idx] == 0x00) {
2325                                                                                                         synclyrics_info = (AvSynclyricsInfo *)malloc(sizeof(AvSynclyricsInfo));
2326
2327                                                                                                         if (synclyrics_info != NULL) {
2328                                                                                                                 if (textEncodingType == AV_ID3V2_UTF8) {
2329                                                                                                                         synclyrics_info->lyric_info = mmfile_malloc(copy_len + 1);
2330                                                                                                                         if (synclyrics_info->lyric_info != NULL) {
2331                                                                                                                                 memset(synclyrics_info->lyric_info, 0, copy_len + 1);
2332                                                                                                                                 memcpy(synclyrics_info->lyric_info, pExtContent + copy_start_pos, copy_len);
2333                                                                                                                                 synclyrics_info->lyric_info[copy_len] = '\0';
2334                                                                                                                         }
2335                                                                                                                 } else {
2336                                                                                                                         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);
2337                                                                                                                 }
2338
2339                                                                                                                 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];
2340                                                                                                                 idx += 4;
2341                                                                                                                 copy_start_pos = tmp + idx + 1;
2342                                                                                                                 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);
2343                                                                                                                 copy_len = 0;
2344                                                                                                                 synclyrics_info_list = g_list_append(synclyrics_info_list, synclyrics_info);
2345                                                                                                         }
2346                                                                                                 }
2347                                                                                                 copy_len++;
2348                                                                                         }
2349                                                                                         pInfo->pSyncLyrics = synclyrics_info_list;
2350                                                                                         pInfo->syncLyricsNum = g_list_length(pInfo->pSyncLyrics);
2351                                                                                 }
2352                                                                         }
2353                                                                 } else {
2354                                                                         debug_msg(RELEASE, "failed to get Synchronised lyrics Info tmp(%d), purelyFramelen - encodingOffSet(%lu)\n", tmp, purelyFramelen - encodingOffSet);
2355                                                                         pInfo->syncLyricsNum = 0;
2356                                                                 }
2357                                                         } else {
2358                                                                 debug_msg(RELEASE, "Synchronised lyrics too small to parse realCpyFrameNum(%d)\n", realCpyFrameNum);
2359                                                                 pInfo->syncLyricsNum = 0;
2360                                                         }
2361                                                         tmp = 0;
2362
2363                                                         //debug_msg(RELEASE, "pInfo->pSyncLyrics returned = (%s), pInfo->syncLyricsNum(%d)\n", pInfo->pSyncLyrics, pInfo->syncLyricsNum);
2364                                                         debug_msg(RELEASE, "pInfo->syncLyricsNum(%d)\n", pInfo->syncLyricsNum);
2365                                                         pInfo->tagV2Info.bSyncLyricsMarked = true;
2366                                                 } else if (strncmp((char *)CompTmp, "USLT", 4) == 0 && pInfo->tagV2Info.bUnsyncLyricsMarked == false) {
2367                                                         char *lang_info = strndup((char *)pExtContent, 3);
2368
2369                                                         if (realCpyFrameNum > 3) {
2370                                                                 realCpyFrameNum -= 3;
2371                                                                 tmp = 3;
2372
2373                                                                 /*find start of lyrics */
2374                                                                 while (1) {
2375                                                                         if (pExtContent[tmp] == 0x00) {
2376                                                                                 if (pExtContent[tmp + 1] == 0x00) {
2377                                                                                         realCpyFrameNum -= 2;
2378                                                                                         tmp += 2;
2379                                                                                 }
2380                                                                                 break;
2381                                                                         } else {
2382                                                                                 realCpyFrameNum--;
2383                                                                                 tmp++;
2384                                                                         }
2385                                                                 }
2386
2387                                                                 /*pExtContent[tmp+1] value should't have encoding value */
2388                                                                 debug_msg(RELEASE, "tpExtContent[%d] %x\n", tmp, pExtContent[tmp]);
2389
2390                                                                 if (pExtContent[tmp] == 0x00 || pExtContent[tmp] == 0xFF || pExtContent[tmp] == 0xFE) {
2391                                                                         if ((IS_ENCODEDBY_UTF16(pExtContent + tmp) || IS_ENCODEDBY_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 2) {
2392                                                                                 while ((NEWLINE_OF_UTF16(pExtContent + tmp) || NEWLINE_OF_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 4) {
2393                                                                                         realCpyFrameNum -= 4;
2394                                                                                         tmp += 4;
2395                                                                                 }
2396
2397                                                                                 if (IS_ENCODEDBY_UTF16(pExtContent + tmp) && (realCpyFrameNum > 2)) {
2398                                                                                         realCpyFrameNum -= 2;
2399                                                                                         tmp += 2;
2400                                                                                         textEncodingType = AV_ID3V2_UTF16;
2401                                                                                 } else if (IS_ENCODEDBY_UTF16_R(pExtContent + tmp) && (realCpyFrameNum > 2)) {
2402                                                                                         realCpyFrameNum -= 2;
2403                                                                                         tmp += 2;
2404                                                                                         textEncodingType = AV_ID3V2_UTF16_BE;
2405                                                                                 } else if (IS_ENCODEDBY_UTF16(pExtContent + tmp + 1) && (realCpyFrameNum > 3)) {
2406                                                                                         realCpyFrameNum -= 3;
2407                                                                                         tmp += 3;
2408                                                                                         textEncodingType = AV_ID3V2_UTF16;
2409                                                                                 } else if (IS_ENCODEDBY_UTF16_R(pExtContent + tmp + 1)  && (realCpyFrameNum > 3)) {
2410                                                                                         realCpyFrameNum -= 3;
2411                                                                                         tmp += 3;
2412                                                                                         textEncodingType = AV_ID3V2_UTF16_BE;
2413                                                                                 } else {
2414                                                                                         debug_msg(RELEASE, "pInfo->pUnsyncLyrics Never Get Here!!\n");
2415                                                                                 }
2416                                                                         } else {
2417                                                                                 while ((pExtContent[tmp] < 0x20) && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
2418                                                                                         realCpyFrameNum--;
2419                                                                                         tmp++;
2420                                                                                 }
2421                                                                                 textEncodingType = AV_ID3V2_ISO_8859;
2422                                                                         }
2423
2424                                                                         char *char_set = NULL;
2425
2426                                                                         debug_msg(RELEASE, "tmp(%d) textEncodingType(%d), realCpyFrameNum(%d)\n", tmp, textEncodingType, realCpyFrameNum);
2427
2428                                                                         if (textEncodingType == AV_ID3V2_ISO_8859) {
2429                                                                                 if (lang_info != NULL && !strcasecmp(lang_info, "KOR")) {
2430                                                                                         char_set = strdup("EUC-KR");
2431                                                                                 } else {
2432                                                                                         char_set = mmfile_get_charset((const char *)&pExtContent[tmp]);
2433                                                                                 }
2434                                                                                 _FREE_EX(lang_info);
2435                                                                         }
2436
2437                                                                         if (char_set == NULL) {
2438                                                                                 pInfo->pUnsyncLyrics = mmfile_string_convert((const char *)&pExtContent[tmp], realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->unsynclyricsLen);
2439                                                                         } else {
2440                                                                                 pInfo->pUnsyncLyrics = mmfile_string_convert((const char *)&pExtContent[tmp], realCpyFrameNum, "UTF-8", char_set, NULL, (unsigned int *)&pInfo->unsynclyricsLen);
2441                                                                                 _FREE_EX(char_set);
2442                                                                         }
2443                                                                 } else {
2444                                                                         debug_msg(RELEASE, "failed to get Unsynchronised lyrics Info tmp(%d), purelyFramelen - encodingOffSet(%lu)\n", tmp, purelyFramelen - encodingOffSet);
2445                                                                         pInfo->unsynclyricsLen = 0;
2446                                                                 }
2447                                                         } else {
2448                                                                 debug_msg(RELEASE, "Unsynchronised lyrics too small to parse realCpyFrameNum(%d)\n", realCpyFrameNum);
2449                                                                 pInfo->unsynclyricsLen = 0;
2450                                                         }
2451                                                         tmp = 0;
2452
2453                                                         debug_msg(RELEASE, "pInfo->pUnsyncLyrics returned = (%s), pInfo->unsynclyricsLen(%d)\n", pInfo->pUnsyncLyrics, pInfo->unsynclyricsLen);
2454                                                         pInfo->tagV2Info.bUnsyncLyricsMarked = true;
2455                                                         mmfile_free(lang_info);
2456                                                 } else if (strncmp((char *)CompTmp, "TCON", 4) == 0 && pInfo->tagV2Info.bGenreMarked == false) {
2457                                                         pInfo->pGenre = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->genreLen);
2458                                                         debug_msg(RELEASE, "pInfo->pGenre returned = (%s), pInfo->genreLen(%d)\n", pInfo->pGenre, pInfo->genreLen);
2459
2460                                                         if ((pInfo->pGenre != NULL) && (pInfo->genreLen > 0)) {
2461                                                                 bool ret = FALSE;
2462                                                                 int int_genre = -1;
2463
2464                                                                 ret = is_numeric(pInfo->pGenre, pInfo->genreLen);
2465
2466                                                                 if (ret == TRUE) {
2467                                                                         ret = safe_atoi(pInfo->pGenre, &int_genre);
2468                                                                         if (ret == TRUE) {
2469                                                                                 debug_msg(RELEASE, "genre information is inteager [%d]\n", int_genre);
2470
2471                                                                                 /*Change int to string */
2472                                                                                 if ((0 <= int_genre) && (int_genre < GENRE_COUNT - 1)) {
2473                                                                                         /*save genreinfo like "(123)". mm_file_id3tag_restore_content_info convert it to string*/
2474                                                                                         char tmp_genre[6] = {0, };      /*ex. "(123)+NULL"*/
2475                                                                                         int tmp_genre_len = 0;
2476
2477                                                                                         memset(tmp_genre, 0, 6);
2478                                                                                         snprintf(tmp_genre, sizeof(tmp_genre), "(%d)", int_genre);
2479
2480                                                                                         tmp_genre_len = strlen(tmp_genre);
2481                                                                                         if (tmp_genre_len > 0) {
2482                                                                                                 if (pInfo->pGenre) _FREE_EX(pInfo->pGenre);
2483                                                                                                 pInfo->pGenre = mmfile_malloc(sizeof(char) * (tmp_genre_len + 1));
2484                                                                                                 if (pInfo->pGenre) {
2485                                                                                                         strncpy(pInfo->pGenre, tmp_genre, tmp_genre_len);
2486                                                                                                         pInfo->pGenre[tmp_genre_len] = 0;
2487                                                                                                 }
2488                                                                                         }
2489                                                                                 }
2490                                                                         } else {
2491                                                                                 debug_msg(RELEASE, "genre information is wrong inteager [%s]\n", pInfo->pGenre);
2492                                                                         }
2493                                                                 }
2494                                                         }
2495
2496                                                         pInfo->tagV2Info.bGenreMarked = true;
2497                                                 } else if (strncmp((char *)CompTmp, "TRCK", 4) == 0 && pInfo->tagV2Info.bTrackNumMarked == false) {
2498                                                         pInfo->pTrackNum = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->tracknumLen);
2499                                                         debug_msg(RELEASE, "pInfo->pTrackNum returned = (%s), pInfo->tracknumLen(%d)\n", pInfo->pTrackNum, pInfo->tracknumLen);
2500                                                         pInfo->tagV2Info.bTrackNumMarked = true;
2501                                                 } else if (strncmp((char *)CompTmp, "TENC", 4) == 0 && pInfo->tagV2Info.bEncByMarked == false) {
2502                                                         pInfo->pEncBy = mmfile_string_convert((char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->encbyLen);
2503                                                         debug_msg(RELEASE, "pInfo->pEncBy returned = (%s), pInfo->encbyLen(%d)\n", pInfo->pEncBy, pInfo->encbyLen);
2504                                                         pInfo->tagV2Info.bEncByMarked = true;
2505                                                 } else if (strncmp((char *)CompTmp, "WXXX", 4) == 0 && pInfo->tagV2Info.bURLMarked == false) {
2506                                                         pInfo->pURL = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->urlLen);
2507                                                         debug_msg(RELEASE, "pInfo->pURL returned = (%s), pInfo->urlLen(%d)\n", pInfo->pURL, pInfo->urlLen);
2508                                                         pInfo->tagV2Info.bURLMarked = true;
2509                                                 } else if (strncmp((char *)CompTmp, "TCOP", 4) == 0 && pInfo->tagV2Info.bCopyRightMarked == false) {
2510                                                         pInfo->pCopyright = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->copyrightLen);
2511                                                         debug_msg(RELEASE, "pInfo->pCopyright returned = (%s), pInfo->copyrightLen(%d)\n", pInfo->pCopyright, pInfo->copyrightLen);
2512                                                         pInfo->tagV2Info.bCopyRightMarked = true;
2513                                                 } else if (strncmp((char *)CompTmp, "TOPE", 4) == 0 && pInfo->tagV2Info.bOriginArtistMarked == false) {
2514                                                         pInfo->pOriginArtist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->originartistLen);
2515                                                         debug_msg(RELEASE, "pInfo->pOriginArtist returned = (%s), pInfo->originartistLen(%d)\n", pInfo->pOriginArtist, pInfo->originartistLen);
2516                                                         pInfo->tagV2Info.bOriginArtistMarked = true;
2517                                                 } else if (strncmp((char *)CompTmp, "TCOM", 4) == 0 && pInfo->tagV2Info.bComposerMarked == false) {
2518                                                         pInfo->pComposer = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->composerLen);
2519                                                         debug_msg(RELEASE, "pInfo->pComposer returned = (%s), pInfo->composerLen(%d)\n", pInfo->pComposer, pInfo->composerLen);
2520                                                         pInfo->tagV2Info.bComposerMarked = true;
2521                                                 } else if (strncmp((char *)CompTmp, "TRDA", 4) == 0 && pInfo->tagV2Info.bRecDateMarked == false) {
2522                                                         pInfo->pRecDate = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->recdateLen);
2523                                                         debug_msg(RELEASE, "pInfo->pRecDate returned = (%s), pInfo->recdateLen(%d)\n", pInfo->pRecDate, pInfo->recdateLen);
2524                                                         pInfo->tagV2Info.bRecDateMarked = true;
2525                                                 } else if (strncmp((char *)CompTmp, "APIC", 4) == 0 && pInfo->tagV2Info.bImageMarked == false && realCpyFrameNum <= 2000000) {
2526                                                         debug_msg(DEBUG, "text encoding %d \n", textEncodingType);
2527
2528                                                         if (pExtContent[0] != '\0') {
2529                                                                 for (inx = 0; inx < MP3_ID3_IMAGE_MIME_TYPE_MAX_LENGTH - 1; inx++)
2530                                                                         pInfo->imageInfo.imageMIMEType[inx] = '\0';/*ini mimetype variable */
2531
2532                                                                 while ((checkImgMimeTypeMax < MP3_ID3_IMAGE_MIME_TYPE_MAX_LENGTH - 1) && pExtContent[checkImgMimeTypeMax] != '\0') {
2533                                                                         pInfo->imageInfo.imageMIMEType[checkImgMimeTypeMax] = pExtContent[checkImgMimeTypeMax];
2534                                                                         checkImgMimeTypeMax++;
2535                                                                 }
2536                                                                 pInfo->imageInfo.imgMimetypeLen = checkImgMimeTypeMax;
2537                                                         } else {
2538                                                                 pInfo->imageInfo.imgMimetypeLen = 0;
2539                                                                 debug_msg(RELEASE, "APIC image's not included to MIME type\n");
2540                                                         }
2541
2542                                                         imgstartOffset += checkImgMimeTypeMax;
2543
2544                                                         if (strncmp(pInfo->imageInfo.imageMIMEType, MIME_PRFIX, strlen(MIME_PRFIX)) != 0) {
2545                                                                 pInfo->imageInfo.imgMimetypeLen = 0;
2546                                                                 debug_error(DEBUG, "APIC NOT VALID");
2547                                                                 continue;
2548                                                         }
2549
2550                                                         if ((pExtContent[imgstartOffset] == '\0') && (realCpyFrameNum - imgstartOffset > 0)) {
2551                                                                 imgstartOffset++;/*endofMIME(1byte) */
2552                                                                 debug_msg(RELEASE, "after scaning Mime type imgstartOffset(%d) value!\n", imgstartOffset);
2553
2554                                                                 if (pExtContent[imgstartOffset] < AV_ID3V2_PICTURE_TYPE_MAX) {
2555                                                                         pInfo->imageInfo.pictureType = pExtContent[imgstartOffset];
2556                                                                 } else {
2557                                                                         debug_msg(RELEASE, "APIC image has invalid picture type(0x%x)\n", pExtContent[imgstartOffset]);
2558                                                                 }
2559                                                                 imgstartOffset++;/*PictureType(1byte) */
2560                                                                 debug_msg(RELEASE, "after scaning PictureType imgstartOffset(%d) value!\n", imgstartOffset);
2561
2562                                                                 if (pExtContent[imgstartOffset] != 0x0) {
2563                                                                         int cur_pos = 0;
2564                                                                         int dis_len = 0;
2565                                                                         int new_dis_len = 0;
2566                                                                         char *tmp_desc = NULL;
2567
2568                                                                         while (1) {
2569                                                                                 if (pExtContent[imgstartOffset + cur_pos] == '\0') {
2570                                                                                         if (realCpyFrameNum < imgstartOffset + cur_pos) {
2571                                                                                                 debug_error(DEBUG, "End of APIC Tag %d %d %d\n", realCpyFrameNum, imgstartOffset, cur_pos);
2572                                                                                                 break;
2573                                                                                         }
2574                                                                                         /*check end of image description*/
2575                                                                                         if ((pExtContent[imgstartOffset + cur_pos + 1] == gTagJPEGHeader[0]) ||
2576                                                                                             (pExtContent[imgstartOffset + cur_pos + 1] == gTagPNGHeader[0])) {
2577                                                                                                 debug_msg(RELEASE, "length of description (%d)", cur_pos);
2578                                                                                                 break;
2579                                                                                         }
2580                                                                                 }
2581                                                                                 cur_pos++;
2582                                                                         }
2583
2584                                                                         dis_len = cur_pos + 1;
2585
2586                                                                         tmp_desc = mmfile_malloc(sizeof(char) * dis_len);
2587                                                                         memcpy(tmp_desc, pExtContent + imgstartOffset, dis_len);
2588
2589                                                                         /*convert description*/
2590                                                                         pInfo->imageInfo.imageDescription = mmfile_string_convert(tmp_desc, dis_len, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&new_dis_len);
2591                                                                         debug_msg(RELEASE, "new_desc %s(%d)\n", pInfo->imageInfo.imageDescription, new_dis_len);
2592                                                                         mmfile_free(tmp_desc);
2593
2594                                                                         pInfo->imageInfo.imgDesLen = new_dis_len; /**/
2595                                                                         imgstartOffset += cur_pos;
2596                                                                 } else {
2597                                                                         pInfo->imageInfo.imgDesLen = 0;
2598                                                                         debug_msg(RELEASE, "APIC image's not included to Description!!!\n");
2599                                                                 }
2600
2601                                                                 if ((pExtContent[imgstartOffset] == '\0') && (realCpyFrameNum - imgstartOffset > 0)) {
2602                                                                         imgstartOffset++; /* endofDesceriptionType(1byte) */
2603
2604                                                                         while (pExtContent[imgstartOffset] == '\0') {   /*some content has useless '\0' in front of picture data */
2605                                                                                 imgstartOffset++;
2606                                                                         }
2607
2608                                                                         debug_msg(RELEASE, "after scaning imgDescription imgstartOffset(%d) value!\n", imgstartOffset);
2609
2610                                                                         if (realCpyFrameNum - imgstartOffset > 0) {
2611                                                                                 pInfo->imageInfo.imageLen = realCpyFrameNum - imgstartOffset;
2612                                                                                 pInfo->imageInfo.pImageBuf = mmfile_malloc(pInfo->imageInfo.imageLen + 1);
2613
2614                                                                                 if (pInfo->imageInfo.pImageBuf != NULL) {
2615                                                                                         memcpy(pInfo->imageInfo.pImageBuf, pExtContent + imgstartOffset, pInfo->imageInfo.imageLen);
2616                                                                                         pInfo->imageInfo.pImageBuf[pInfo->imageInfo.imageLen] = 0;
2617                                                                                 }
2618
2619                                                                                 if (IS_INCLUDE_URL(pInfo->imageInfo.imageMIMEType))
2620                                                                                         pInfo->imageInfo.bURLInfo = true; /*if mimetype is "-->", image date has an URL */
2621                                                                         } else {
2622                                                                                 debug_msg(RELEASE, "No APIC image!! realCpyFrameNum(%d) - imgstartOffset(%d)\n", realCpyFrameNum, imgstartOffset);
2623                                                                         }
2624                                                                         debug_msg(RELEASE, "pInfo->imageInfo.imageLen(%d), imgstartOffset(%d)!\n", pInfo->imageInfo.imageLen, imgstartOffset);
2625                                                                 } else {
2626                                                                         debug_msg(RELEASE, "pExtContent[imgstartOffset](%d) value should setted NULL value for end of description! realCpyFrameNum - imgstartOffset(%d)\n",
2627                                                                                         pExtContent[imgstartOffset], realCpyFrameNum - imgstartOffset);
2628                                                                 }
2629                                                         } else {
2630                                                                 debug_msg(RELEASE, "pExtContent[imgstartOffset](%d) value should setted NULL value for end of mimetype! realCpyFrameNum - imgstartOffset(%d)\n",
2631                                                                                         pExtContent[imgstartOffset], realCpyFrameNum - imgstartOffset);
2632                                                         }
2633
2634                                                         checkImgMimeTypeMax = 0;
2635                                                         inx = 0;
2636                                                         imgstartOffset = 0;
2637                                                         pInfo->tagV2Info.bImageMarked = true;
2638
2639                                                 } else {
2640                                                         debug_msg(RELEASE, "CompTmp(%s) This Frame ID currently not Supports!!\n", CompTmp);
2641                                                 }
2642                                         }
2643
2644                                 } else {
2645                                         debug_msg(RELEASE, "All of the pExtContent Values are NULL\n");
2646                                 }
2647                         } else {
2648                                 curPos += purelyFramelen;
2649                                 if (purelyFramelen != 0)
2650                                         needToloopv2taglen = MP3_TAGv2_23_TXT_HEADER_LEN;
2651
2652                                 debug_msg(RELEASE, "This Frame's size is Zero! purelyFramelen(%lu)\n", purelyFramelen);
2653                         }
2654
2655                         if (pExtContent)        _FREE_EX(pExtContent);
2656                         memset(CompTmp, 0, 4);
2657
2658                         if (curPos < taglen) {
2659                                 needToloopv2taglen -= oneFrameLen;
2660                                 v2numOfFrames++;
2661                         } else
2662                                 needToloopv2taglen = MP3_TAGv2_23_TXT_HEADER_LEN;
2663                         oneFrameLen = 0;
2664                         encodingOffSet = 0;
2665                         realCpyFrameNum = 0;
2666                         textEncodingType = 0;
2667                         purelyFramelen = 0;
2668
2669                 }
2670         }
2671
2672         release_characterset_array(charset_array);
2673
2674         if (taglen)
2675                 return true;
2676         else
2677                 return false;
2678
2679 }
2680
2681 EXPORT_API
2682 bool mm_file_id3tag_parse_v224(AvFileContentInfo *pInfo, unsigned char *buffer)
2683 {
2684         unsigned long taglen = 0;
2685         unsigned long needToloopv2taglen;
2686         unsigned long oneFrameLen = 0;
2687         unsigned long v2numOfFrames = 0;
2688         unsigned long curPos = 0;
2689         char CompTmp[5];
2690         unsigned char *pExtContent = NULL;
2691         unsigned long purelyFramelen = 0;
2692         unsigned int encodingOffSet = 0;
2693         int inx = 0, realCpyFrameNum = 0, checkImgMimeTypeMax = 0, imgstartOffset = 0,  tmp = 0;
2694         int textEncodingType = 0;
2695         char **charset_array = NULL;
2696         const char *MIME_PRFIX = "image/";
2697
2698         make_characterset_array(&charset_array);
2699
2700         init_content_info(pInfo);
2701
2702         taglen = pInfo->tagV2Info.tagLen;
2703         needToloopv2taglen = taglen - MP3_TAGv2_HEADER_LEN;
2704         curPos = MP3_TAGv2_HEADER_LEN;
2705
2706         debug_msg(RELEASE, "ID3tag v224--------------------------------------------------------------\n");
2707
2708         /* check Extended Header */
2709         if (buffer[5] & 0x40) {
2710                 /* if extended header exists, skip it*/
2711                 int extendedHeaderLen = (unsigned long)buffer[10] << 21 | (unsigned long)buffer[11] << 14 | (unsigned long)buffer[12] << 7  | (unsigned long)buffer[13];
2712
2713                 debug_msg(RELEASE, "--------------- extendedHeaderLen = %d\n", extendedHeaderLen);
2714
2715                 if (extendedHeaderLen > (int)(taglen - curPos)) {
2716                         debug_error(DEBUG, "extended header too long.\n");
2717                 } else {
2718                         curPos += extendedHeaderLen;
2719                 }
2720         }
2721
2722         if (needToloopv2taglen - MP3_TAGv2_23_TXT_HEADER_LEN > MP3_TAGv2_23_TXT_HEADER_LEN) {
2723                 v2numOfFrames = 1;
2724                 while (needToloopv2taglen > MP3_TAGv2_23_TXT_HEADER_LEN) {
2725                         if ((buffer[curPos] < '0' || buffer[curPos] > 'Z') || (buffer[curPos + 1] < '0' || buffer[curPos + 1] > 'Z')
2726                             || (buffer[curPos + 2] < '0' || buffer[curPos + 2] > 'Z') || (buffer[curPos + 3] < '0' || buffer[curPos + 3] > 'Z'))
2727                                 break;
2728
2729                         memcpy(CompTmp, &buffer[curPos], 4);
2730
2731                         CompTmp[4] = 0;
2732                         oneFrameLen = MP3_TAGv2_23_TXT_HEADER_LEN;
2733                         oneFrameLen += (unsigned long)buffer[4 + curPos] << 21 | (unsigned long)buffer[5 + curPos] << 14
2734                                                 | (unsigned long)buffer[6 + curPos] << 7 | (unsigned long)buffer[7 + curPos];
2735                         if (oneFrameLen > taglen - curPos)
2736                                 break;
2737
2738                         purelyFramelen = oneFrameLen - MP3_TAGv2_23_TXT_HEADER_LEN;
2739                         curPos += MP3_TAGv2_23_TXT_HEADER_LEN;
2740
2741                         debug_msg(RELEASE, "-----------------------------------------------------------------------------------\n");
2742
2743                         if (oneFrameLen > MP3_TAGv2_23_TXT_HEADER_LEN && purelyFramelen <= taglen - curPos) {
2744                                 curPos += purelyFramelen;
2745
2746                                 /*in case of UTF 16 encoding */
2747                                 /*buffer+(curPos-purelyFramelen) data should '0x01' but in order to expansion, we don't accurately check the value. */
2748                                 if (IS_ENCODEDBY_UTF16(buffer + (curPos - purelyFramelen))) {
2749                                         encodingOffSet = 2;
2750                                         textEncodingType = AV_ID3V2_UTF16;
2751                                 } else if (IS_ENCODEDBY_UTF16_R(buffer + (curPos - purelyFramelen))) {
2752                                         encodingOffSet = 2;
2753                                         textEncodingType = AV_ID3V2_UTF16_BE;
2754                                 } else if (IS_ENCODEDBY_UTF16(buffer + (curPos - purelyFramelen + 1))) {
2755                                         encodingOffSet = 3;
2756                                         textEncodingType = AV_ID3V2_UTF16;
2757                                 } else if (IS_ENCODEDBY_UTF16_R(buffer + (curPos - purelyFramelen + 1))) {
2758                                         encodingOffSet = 3;
2759                                         textEncodingType = AV_ID3V2_UTF16_BE;
2760                                 } else {
2761                                         /*in case of UTF-16 BE encoding */
2762                                         if (buffer[curPos - purelyFramelen] == 0x02) {
2763                                                 encodingOffSet = 1;
2764                                                 while ((buffer[curPos - purelyFramelen + encodingOffSet] == '\0') && (encodingOffSet < purelyFramelen))
2765                                                         encodingOffSet++;/*null skip! */
2766                                                 textEncodingType = AV_ID3V2_UTF16_BE;
2767                                         }
2768                                         /*in case of UTF8 encoding */
2769                                         else if (buffer[curPos - purelyFramelen] == 0x03) {
2770                                                 encodingOffSet = 1;
2771                                                 while ((buffer[curPos - purelyFramelen + encodingOffSet] == '\0') && (encodingOffSet < purelyFramelen))
2772                                                         encodingOffSet++;/*null skip! */
2773                                                 textEncodingType = AV_ID3V2_UTF8;
2774                                         }
2775                                         /*in case of ISO-8859-1 encoding */
2776                                         else {
2777                                                 /*buffer+(curPos-purelyFramelen) data should 0x00 but in order to expansion, we don't accurately check the value. */
2778                                                 encodingOffSet = 1;
2779                                                 while ((buffer[curPos - purelyFramelen + encodingOffSet] < 0x20) && (encodingOffSet < purelyFramelen))
2780                                                         encodingOffSet++;/*less than 0x20 value skip! */
2781                                                 textEncodingType = AV_ID3V2_ISO_8859;
2782                                         }
2783                                 }
2784
2785                                 if (encodingOffSet < purelyFramelen) {
2786                                         realCpyFrameNum = purelyFramelen - encodingOffSet;
2787                                         pExtContent = mmfile_malloc(realCpyFrameNum + 3);
2788
2789                                         if (pExtContent == NULL) {
2790                                                 debug_error(DEBUG, "out of memoryu for id3tag parse\n");
2791                                                 continue;
2792                                         }
2793
2794                                         memset(pExtContent, '\0', realCpyFrameNum + 3);
2795
2796                                         if (textEncodingType != AV_ID3V2_UTF16 && textEncodingType != AV_ID3V2_UTF16_BE) {
2797                                                 if (CompTmp[0] == 'T' || (strcmp(CompTmp, "APIC") == 0)) {
2798                                                         debug_msg(RELEASE, "get the new text ecoding type\n");
2799                                                         textEncodingType = buffer[curPos - purelyFramelen + encodingOffSet - 1];
2800                                                 }
2801                                         }
2802
2803                                         if (textEncodingType > AV_ID3V2_MAX) {
2804                                                 debug_msg(DEBUG, "WRONG ENCOIDNG TYPE [%d], FRAME[%s]\n", textEncodingType, (char *)CompTmp);
2805                                                 continue;
2806                                         }
2807
2808                                         memcpy(pExtContent, &buffer[curPos - purelyFramelen + encodingOffSet], purelyFramelen - encodingOffSet);
2809
2810                                         if (realCpyFrameNum > 0) {
2811                                                 if (strncmp((char *)CompTmp, "TIT2", 4) == 0 && pInfo->tagV2Info.bTitleMarked == false) {
2812                                                         if (textEncodingType == AV_ID3V2_UTF8) {
2813                                                                 pInfo->pTitle = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
2814                                                                 if (pInfo->pTitle) {
2815                                                                         memcpy(pInfo->pTitle, pExtContent, realCpyFrameNum);
2816                                                                         pInfo->pTitle[realCpyFrameNum] = '\0';
2817                                                                         /*string copy with '\0'*/
2818                                                                         pInfo->titleLen = realCpyFrameNum;
2819                                                                         _STRNCPY_EX(pInfo->pTitle, pExtContent, pInfo->titleLen);
2820                                                                 }
2821                                                         } else {
2822                                                                 pInfo->pTitle = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->titleLen);
2823                                                         }
2824
2825                                                         debug_msg(RELEASE, "pInfo->pTitle returned = (%s), pInfo->titleLen(%d)\n", pInfo->pTitle, pInfo->titleLen);
2826                                                         pInfo->tagV2Info.bTitleMarked = true;
2827
2828                                                 } else if (strncmp((char *)CompTmp, "TPE1", 4) == 0 && pInfo->tagV2Info.bArtistMarked == false) {
2829                                                         if (textEncodingType == AV_ID3V2_UTF8) {
2830                                                                 pInfo->pArtist = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
2831                                                                 if (pInfo->pArtist) {
2832                                                                         memcpy(pInfo->pArtist, pExtContent, realCpyFrameNum);
2833                                                                         pInfo->pArtist[realCpyFrameNum] = '\0';
2834                                                                         /*string copy with '\0'*/
2835                                                                         pInfo->artistLen = realCpyFrameNum;
2836                                                                         _STRNCPY_EX(pInfo->pArtist, pExtContent, pInfo->artistLen);
2837                                                                 }
2838                                                         } else {
2839                                                                 pInfo->pArtist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->artistLen);
2840                                                         }
2841
2842
2843                                                         debug_msg(RELEASE, "pInfo->pArtist returned = (%s), pInfo->artistLen(%d)\n", pInfo->pArtist, pInfo->artistLen);
2844                                                         pInfo->tagV2Info.bArtistMarked = true;
2845                                                 } else if (strncmp((char *)CompTmp, "TPE2", 4) == 0 && pInfo->tagV2Info.bAlbum_ArtistMarked == false) {
2846                                                         if (textEncodingType == AV_ID3V2_UTF8) {
2847                                                                 pInfo->pAlbum_Artist = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
2848                                                                 if (pInfo->pAlbum_Artist) {
2849                                                                         memcpy(pInfo->pAlbum_Artist, pExtContent, realCpyFrameNum);
2850                                                                         pInfo->pAlbum_Artist[realCpyFrameNum] = '\0';
2851                                                                         /*string copy with '\0'*/
2852                                                                         pInfo->album_artistLen = realCpyFrameNum;
2853                                                                         _STRNCPY_EX(pInfo->pAlbum_Artist, pExtContent, pInfo->album_artistLen);
2854                                                                 }
2855                                                         } else {
2856                                                                 pInfo->pAlbum_Artist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->album_artistLen);
2857                                                         }
2858
2859                                                         debug_msg(RELEASE, "pInfo->pAlbum_Artist returned = (%s), pInfo->album_artistLen(%d)\n", pInfo->pAlbum_Artist, pInfo->album_artistLen);
2860                                                         pInfo->tagV2Info.bAlbum_ArtistMarked = true;
2861                                                 } else if (strncmp((char *)CompTmp, "TPE3", 4) == 0 && pInfo->tagV2Info.bConductorMarked == false) {
2862                                                         if (textEncodingType == AV_ID3V2_UTF8) {
2863                                                                 pInfo->pConductor = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
2864                                                                 if (pInfo->pConductor) {
2865                                                                         memcpy(pInfo->pConductor, pExtContent, realCpyFrameNum);
2866                                                                         pInfo->pConductor[realCpyFrameNum] = '\0';
2867                                                                         /*string copy with '\0'*/
2868                                                                         pInfo->conductorLen = realCpyFrameNum;
2869                                                                         _STRNCPY_EX(pInfo->pConductor, pExtContent, pInfo->conductorLen);
2870                                                                 }
2871                                                         } else {
2872                                                                 pInfo->pConductor = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->conductorLen);
2873                                                         }
2874
2875                                                         debug_msg(RELEASE, "pInfo->pConductor returned = (%s), pInfo->conductorLen(%d)\n", pInfo->pConductor, pInfo->conductorLen);
2876                                                         pInfo->tagV2Info.bConductorMarked = true;
2877                                                 } else if (strncmp((char *)CompTmp, "TALB", 4) == 0 && pInfo->tagV2Info.bAlbumMarked == false) {
2878                                                         if (textEncodingType == AV_ID3V2_UTF8) {
2879                                                                 pInfo->pAlbum = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
2880                                                                 if (pInfo->pAlbum) {
2881                                                                         memcpy(pInfo->pAlbum, pExtContent, realCpyFrameNum);
2882                                                                         pInfo->pAlbum[realCpyFrameNum] = '\0';
2883                                                                         /*string copy with '\0'*/
2884                                                                         pInfo->albumLen = realCpyFrameNum;
2885                                                                         _STRNCPY_EX(pInfo->pAlbum, pExtContent, pInfo->albumLen);
2886                                                                 }
2887                                                         } else {
2888                                                                 pInfo->pAlbum = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->albumLen);
2889                                                         }
2890
2891                                                         debug_msg(RELEASE, "pInfo->pAlbum returned = (%s), pInfo->albumLen(%d)\n", pInfo->pAlbum, pInfo->albumLen);
2892                                                         pInfo->tagV2Info.bAlbumMarked = true;
2893                                                 } else if (strncmp((char *)CompTmp, "TYER", 4) == 0 && pInfo->tagV2Info.bYearMarked == false) { /*TODO. TYER is replaced by the TDRC. but many files use TYER in v2.4 */
2894                                                         if (textEncodingType == AV_ID3V2_UTF8) {
2895                                                                 pInfo->pYear = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
2896                                                                 if (pInfo->pYear) {
2897                                                                         memcpy(pInfo->pYear, pExtContent, realCpyFrameNum);
2898                                                                         pInfo->pYear[realCpyFrameNum] = '\0';
2899                                                                         /*string copy with '\0'*/
2900                                                                         pInfo->yearLen = realCpyFrameNum;
2901                                                                         _STRNCPY_EX(pInfo->pYear, pExtContent, pInfo->yearLen);
2902                                                                 }
2903                                                         } else {
2904                                                                 pInfo->pYear = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->yearLen);
2905                                                         }
2906
2907                                                         debug_msg(RELEASE, "pInfo->pYear returned = (%s), pInfo->yearLen(%d)\n", pInfo->pYear, pInfo->yearLen);
2908                                                         pInfo->tagV2Info.bYearMarked = true;
2909                                                 } else if (strncmp((char *)CompTmp, "COMM", 4) == 0 && pInfo->tagV2Info.bDescriptionMarked == false) {
2910                                                         if (realCpyFrameNum > 3) {
2911                                                                 realCpyFrameNum -= 3;
2912                                                                 tmp = 3;
2913
2914                                                                 if (textEncodingType == AV_ID3V2_UTF16 || textEncodingType == AV_ID3V2_UTF16_BE) {
2915                                                                         while ((NEWLINE_OF_UTF16(pExtContent + tmp) || NEWLINE_OF_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 4) {
2916                                                                                 realCpyFrameNum -= 4;
2917                                                                                 tmp += 4;
2918                                                                         }
2919
2920                                                                         if ((IS_ENCODEDBY_UTF16(pExtContent + tmp) || IS_ENCODEDBY_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 2) {
2921                                                                                 realCpyFrameNum -= 2;
2922                                                                                 tmp += 2;
2923                                                                                 textEncodingType = AV_ID3V2_UTF16;
2924                                                                         } else {
2925                                                                                 debug_msg(RELEASE, "pInfo->pComment Never Get Here!!\n");
2926                                                                         }
2927                                                                 } else if (textEncodingType == AV_ID3V2_UTF8) {
2928                                                                         while (pExtContent[tmp] < 0x20 && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
2929                                                                                 realCpyFrameNum--;
2930                                                                                 tmp++;
2931                                                                         }
2932                                                                         textEncodingType = AV_ID3V2_UTF8;
2933                                                                 } else {
2934                                                                         while (pExtContent[tmp] < 0x20 && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
2935                                                                                 realCpyFrameNum--;
2936                                                                                 tmp++;
2937                                                                         }
2938                                                                         textEncodingType = AV_ID3V2_ISO_8859;
2939                                                                 }
2940
2941                                                                 debug_msg(RELEASE, "tmp(%d) textEncodingType(%d), realCpyFrameNum(%d)\n", tmp, textEncodingType, realCpyFrameNum);
2942
2943                                                                 if (textEncodingType == AV_ID3V2_UTF8) {
2944                                                                         pInfo->pComment = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
2945                                                                         if (pInfo->pComment) {
2946                                                                                 memset(pInfo->pComment, 0, (realCpyFrameNum + 2));
2947                                                                                 memcpy(pInfo->pComment, pExtContent + tmp, realCpyFrameNum);
2948                                                                                 pInfo->pComment[realCpyFrameNum] = '\0';
2949                                                                                 /*string copy with '\0'*/
2950                                                                                 pInfo->commentLen = realCpyFrameNum;
2951                                                                                 _STRNCPY_EX(pInfo->pComment, pExtContent, pInfo->commentLen);
2952                                                                         }
2953                                                                 } else {
2954                                                                         pInfo->pComment = mmfile_string_convert((const char *)&pExtContent[tmp], realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->commentLen);
2955                                                                 }
2956                                                         } else {
2957                                                                 debug_msg(RELEASE, "Description info too small to parse realCpyFrameNum(%d)\n", realCpyFrameNum);
2958                                                         }
2959
2960                                                         tmp = 0;
2961
2962                                                         debug_msg(RELEASE, "pInfo->pComment returned = (%s), pInfo->commentLen(%d)\n", pInfo->pComment, pInfo->commentLen);
2963                                                         pInfo->tagV2Info.bDescriptionMarked = true;
2964                                                 } else if (strncmp((char *)CompTmp, "SYLT", 4) == 0 && pInfo->tagV2Info.bSyncLyricsMarked == false) {
2965                                                         int idx = 0;
2966                                                         int copy_len = 0;
2967                                                         int copy_start_pos = tmp;
2968                                                         AvSynclyricsInfo *synclyrics_info = NULL;
2969                                                         GList *synclyrics_info_list = NULL;
2970
2971                                                         if (realCpyFrameNum > 5) {
2972                                                                 realCpyFrameNum -= 5;
2973                                                                 tmp = 5;
2974
2975                                                                 if (textEncodingType == AV_ID3V2_UTF16 || textEncodingType == AV_ID3V2_UTF16_BE) {
2976                                                                         while ((NEWLINE_OF_UTF16(pExtContent + tmp) || NEWLINE_OF_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 4) {
2977                                                                                 realCpyFrameNum -= 4;
2978                                                                                 tmp += 4;
2979                                                                         }
2980
2981                                                                         if ((IS_ENCODEDBY_UTF16(pExtContent + tmp) || IS_ENCODEDBY_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 2) {
2982                                                                                 realCpyFrameNum -= 2;
2983                                                                                 tmp += 2;
2984                                                                                 textEncodingType = AV_ID3V2_UTF16;
2985                                                                         } else {
2986                                                                                 debug_msg(RELEASE, "pInfo->pSyncLyrics Never Get Here!!\n");
2987                                                                         }
2988                                                                 } else if (textEncodingType == AV_ID3V2_UTF8) {
2989                                                                         while (pExtContent[tmp] < 0x20 && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
2990                                                                                 realCpyFrameNum--;
2991                                                                                 tmp++;
2992                                                                         }
2993                                                                         textEncodingType = AV_ID3V2_UTF8;
2994                                                                 } else {
2995                                                                         while (pExtContent[tmp] < 0x20 && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
2996                                                                                 realCpyFrameNum--;
2997                                                                                 tmp++;
2998                                                                         }
2999                                                                         textEncodingType = AV_ID3V2_ISO_8859;
3000                                                                 }
3001
3002                                                                 debug_msg(RELEASE, "tmp(%d) textEncodingType(%d), realCpyFrameNum(%d)\n", tmp, textEncodingType, realCpyFrameNum);
3003
3004                                                                 if (realCpyFrameNum < MMFILE_SYNC_LYRIC_INFO_MIN_LEN) {
3005                                                                         debug_msg(RELEASE, "failed to get Synchronised lyrics Info realCpyFramNum(%d)\n", realCpyFrameNum);
3006                                                                         pInfo->syncLyricsNum = 0;
3007                                                                 } else {
3008                                                                         if (textEncodingType == AV_ID3V2_UTF16) {
3009                                                                                 debug_warning(DEBUG, "[AV_ID3V2_UTF16] not implemented\n");
3010                                                                         } else if (textEncodingType == AV_ID3V2_UTF16_BE) {
3011                                                                                 debug_warning(DEBUG, "[AV_ID3V2_UTF16_BE] not implemented\n");
3012                                                                         } else {
3013                                                                                 for (idx = 0; idx < realCpyFrameNum; idx++) {
3014                                                                                         if (pExtContent[tmp + idx] == 0x00) {
3015                                                                                                 synclyrics_info = (AvSynclyricsInfo *)malloc(sizeof(AvSynclyricsInfo));
3016
3017                                                                                                 if (textEncodingType == AV_ID3V2_UTF8) {
3018                                                                                                         synclyrics_info->lyric_info = mmfile_malloc(copy_len + 1);
3019                                                                                                         if (synclyrics_info->lyric_info) {
3020                                                                                                                 memset(synclyrics_info->lyric_info, 0, copy_len + 1);
3021                                                                                                                 memcpy(synclyrics_info->lyric_info, pExtContent + copy_start_pos, copy_len);
3022                                                                                                                 synclyrics_info->lyric_info[copy_len] = '\0';
3023                                                                                                         }
3024                                                                                                 } else {
3025                                                                                                         synclyrics_info->lyric_info = mmfile_string_convert((const char *)&pExtContent[copy_start_pos], copy_len, "UTF-8", charset_array[textEncodingType], NULL, NULL);
3026                                                                                                 }
3027
3028                                                                                                 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];
3029                                                                                                 idx += 4;
3030                                                                                                 copy_start_pos = tmp + idx + 1;
3031                                                                                                 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);
3032                                                                                                 copy_len = 0;
3033                                                                                                 synclyrics_info_list = g_list_append(synclyrics_info_list, synclyrics_info);
3034                                                                                         }
3035                                                                                         copy_len++;
3036                                                                                 }
3037                                                                                 pInfo->pSyncLyrics = synclyrics_info_list;
3038                                                                                 pInfo->syncLyricsNum = g_list_length(pInfo->pSyncLyrics);
3039                                                                         }
3040                                                                 }
3041                                                         } else {
3042                                                                 debug_msg(RELEASE, "SyncLyrics info too small to parse realCpyFrameNum(%d)\n", realCpyFrameNum);
3043                                                         }
3044
3045                                                         tmp = 0;
3046                                                         pInfo->tagV2Info.bSyncLyricsMarked = true;
3047                                                 } else if (strncmp((char *)CompTmp, "USLT", 4) == 0 && pInfo->tagV2Info.bUnsyncLyricsMarked == false) {
3048                                                         if (realCpyFrameNum > 3) {
3049                                                                 realCpyFrameNum -= 3;
3050                                                                 tmp = 3;
3051
3052                                                                 if (textEncodingType == AV_ID3V2_UTF16 || textEncodingType == AV_ID3V2_UTF16_BE) {
3053                                                                         while ((NEWLINE_OF_UTF16(pExtContent + tmp) || NEWLINE_OF_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 4) {
3054                                                                                 realCpyFrameNum -= 4;
3055                                                                                 tmp += 4;
3056                                                                         }
3057
3058                                                                         if ((IS_ENCODEDBY_UTF16(pExtContent + tmp) || IS_ENCODEDBY_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 2) {
3059                                                                                 realCpyFrameNum -= 2;
3060                                                                                 tmp += 2;
3061                                                                                 textEncodingType = AV_ID3V2_UTF16;
3062                                                                         } else {
3063                                                                                 debug_msg(RELEASE, "pInfo->pUnsyncLyrics Never Get Here!!\n");
3064                                                                         }
3065                                                                 } else if (textEncodingType == AV_ID3V2_UTF8) {
3066                                                                         while (pExtContent[tmp] < 0x20 && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
3067                                                                                 realCpyFrameNum--;
3068                                                                                 tmp++;
3069                                                                         }
3070                                                                         textEncodingType = AV_ID3V2_UTF8;
3071                                                                 } else {
3072                                                                         while (pExtContent[tmp] < 0x20 && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
3073                                                                                 realCpyFrameNum--;
3074                                                                                 tmp++;
3075                                                                         }
3076                                                                         textEncodingType = AV_ID3V2_ISO_8859;
3077                                                                 }
3078
3079                                                                 debug_msg(RELEASE, "tmp(%d) textEncodingType(%d), realCpyFrameNum(%d)\n", tmp, textEncodingType, realCpyFrameNum);
3080
3081                                                                 if (textEncodingType == AV_ID3V2_UTF8) {
3082                                                                         pInfo->pUnsyncLyrics = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3083
3084                                                                         if (pInfo->pUnsyncLyrics != NULL) {
3085                                                                                 memset(pInfo->pUnsyncLyrics, 0, (realCpyFrameNum + 2));
3086                                                                                 memcpy(pInfo->pUnsyncLyrics, pExtContent + tmp, realCpyFrameNum);
3087                                                                                 pInfo->pUnsyncLyrics[realCpyFrameNum] = '\0';
3088                                                                                 /*string copy with '\0'*/
3089                                                                                 pInfo->unsynclyricsLen = realCpyFrameNum;
3090                                                                                 _STRNCPY_EX(pInfo->pUnsyncLyrics, pExtContent, pInfo->unsynclyricsLen);
3091                                                                         } else {
3092                                                                                 debug_error(DEBUG, "out of memoryu for SyncLyrics\n");
3093                                                                         }
3094                                                                 } else {
3095                                                                         pInfo->pUnsyncLyrics = mmfile_string_convert((const char *)&pExtContent[tmp], realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->unsynclyricsLen);
3096                                                                 }
3097                                                         } else {
3098                                                                 debug_msg(RELEASE, "Description info too small to parse realCpyFrameNum(%d)\n", realCpyFrameNum);
3099                                                         }
3100
3101                                                         tmp = 0;
3102
3103                                                         debug_msg(RELEASE, "pInfo->pUnsyncLyrics returned = (%s), pInfo->unsynclyricsLen(%d)\n", pInfo->pUnsyncLyrics, pInfo->unsynclyricsLen);
3104                                                         pInfo->tagV2Info.bDescriptionMarked = true;
3105                                                 } else if (strncmp((char *)CompTmp, "TCON", 4) == 0 && pInfo->tagV2Info.bGenreMarked == false) {
3106                                                         if (textEncodingType == AV_ID3V2_UTF8) {
3107                                                                 pInfo->pGenre = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3108                                                                 if (pInfo->pGenre) {
3109                                                                         memcpy(pInfo->pGenre, pExtContent, realCpyFrameNum);
3110                                                                         pInfo->pGenre[realCpyFrameNum] = '\0';
3111                                                                         /*string copy with '\0'*/
3112                                                                         pInfo->genreLen = realCpyFrameNum;
3113                                                                         _STRNCPY_EX(pInfo->pGenre, pExtContent, pInfo->genreLen);
3114                                                                 }
3115                                                         } else {
3116                                                                 pInfo->pGenre = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->genreLen);
3117                                                         }
3118
3119                                                         debug_msg(RELEASE, "pInfo->pGenre returned = (%s), pInfo->genreLen(%d)\n", pInfo->pGenre, pInfo->genreLen);
3120
3121                                                         if ((pInfo->pGenre != NULL) && (pInfo->genreLen > 0)) {
3122                                                                 bool ret = FALSE;
3123                                                                 int int_genre = -1;
3124
3125                                                                 ret = is_numeric(pInfo->pGenre, pInfo->genreLen);
3126
3127                                                                 if (ret == TRUE) {
3128                                                                         ret = safe_atoi(pInfo->pGenre, &int_genre);
3129                                                                         if (ret == TRUE) {
3130                                                                                 debug_msg(RELEASE, "genre information is inteager [%d]\n", int_genre);
3131
3132                                                                                 /*Change int to string */
3133                                                                                 if ((0 <= int_genre) && (int_genre < GENRE_COUNT - 1)) {
3134                                                                                         /*save genreinfo like "(123)". mm_file_id3tag_restore_content_info convert it to string*/
3135                                                                                         char tmp_genre[6] = {0, };      /*ex. "(123)+NULL"*/
3136                                                                                         int tmp_genre_len = 0;
3137
3138                                                                                         memset(tmp_genre, 0, 6);
3139                                                                                         snprintf(tmp_genre, sizeof(tmp_genre), "(%d)", int_genre);
3140
3141                                                                                         tmp_genre_len = strlen(tmp_genre);
3142                                                                                         if (tmp_genre_len > 0) {
3143                                                                                                 if (pInfo->pGenre) _FREE_EX(pInfo->pGenre);
3144                                                                                                 pInfo->pGenre = mmfile_malloc(sizeof(char) * (tmp_genre_len + 1));
3145                                                                                                 if (pInfo->pGenre) {
3146                                                                                                         strncpy(pInfo->pGenre, tmp_genre, tmp_genre_len);
3147                                                                                                         pInfo->pGenre[tmp_genre_len] = 0;
3148                                                                                                 }
3149                                                                                         }
3150                                                                                 }
3151                                                                         } else {
3152                                                                                 debug_msg(RELEASE, "genre information is wrong inteager [%s]\n", pInfo->pGenre);
3153                                                                         }
3154                                                                 }
3155                                                         }
3156
3157                                                         pInfo->tagV2Info.bGenreMarked = true;
3158                                                 } else if (strncmp((char *)CompTmp, "TRCK", 4) == 0 && pInfo->tagV2Info.bTrackNumMarked == false) {
3159                                                         if (textEncodingType == AV_ID3V2_UTF8) {
3160                                                                 pInfo->pTrackNum = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3161                                                                 if (pInfo->pTrackNum != NULL) {
3162                                                                         memcpy(pInfo->pTrackNum, pExtContent, realCpyFrameNum);
3163                                                                         pInfo->pTrackNum[realCpyFrameNum] = '\0';
3164                                                                         /*string copy with '\0'*/
3165                                                                         pInfo->tracknumLen = realCpyFrameNum;
3166                                                                         _STRNCPY_EX(pInfo->pTrackNum, pExtContent, pInfo->tracknumLen);
3167                                                                 }
3168                                                         } else {
3169                                                                 pInfo->pTrackNum = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->tracknumLen);
3170                                                         }
3171
3172                                                         debug_msg(RELEASE, "pInfo->pTrackNum returned = (%s), pInfo->tracknumLen(%d)\n", pInfo->pTrackNum, pInfo->tracknumLen);
3173                                                         pInfo->tagV2Info.bTrackNumMarked = true;
3174                                                 } else if (strncmp((char *)CompTmp, "TENC", 4) == 0 && pInfo->tagV2Info.bEncByMarked == false) {
3175                                                         if (textEncodingType == AV_ID3V2_UTF8) {
3176                                                                 pInfo->pEncBy = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3177                                                                 if (pInfo->pEncBy != NULL) {
3178                                                                         memcpy(pInfo->pEncBy, pExtContent, realCpyFrameNum);
3179                                                                         pInfo->pEncBy[realCpyFrameNum] = '\0';
3180                                                                         /*string copy with '\0'*/
3181                                                                         pInfo->encbyLen = realCpyFrameNum;
3182                                                                         _STRNCPY_EX(pInfo->pEncBy, pExtContent, pInfo->encbyLen);
3183                                                                 }
3184                                                         } else {
3185                                                                 pInfo->pEncBy = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->encbyLen);
3186                                                         }
3187
3188                                                         debug_msg(RELEASE, "pInfo->pEncBy returned = (%s), pInfo->encbyLen(%d)\n", pInfo->pEncBy, pInfo->encbyLen);
3189                                                         pInfo->tagV2Info.bEncByMarked = true;
3190                                                 } else if (strncmp((char *)CompTmp, "WXXX", 4) == 0 && pInfo->tagV2Info.bURLMarked == false) {
3191                                                         if (textEncodingType == AV_ID3V2_UTF8) {
3192                                                                 pInfo->pURL = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3193                                                                 if (pInfo->pURL != NULL) {
3194                                                                         memcpy(pInfo->pURL, pExtContent, realCpyFrameNum);
3195                                                                         pInfo->pURL[realCpyFrameNum] = '\0';
3196                                                                         /*string copy with '\0'*/
3197                                                                         pInfo->urlLen = realCpyFrameNum;
3198                                                                         _STRNCPY_EX(pInfo->pURL, pExtContent, pInfo->urlLen);
3199                                                                 }
3200                                                         } else {
3201                                                                 pInfo->pURL = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->urlLen);
3202                                                         }
3203
3204                                                         debug_msg(RELEASE, "pInfo->pURL returned = (%s), pInfo->urlLen(%d)\n", pInfo->pURL, pInfo->urlLen);
3205                                                         pInfo->tagV2Info.bURLMarked = true;
3206                                                 } else if (strncmp((char *)CompTmp, "TCOP", 4) == 0 && pInfo->tagV2Info.bCopyRightMarked == false) {
3207                                                         if (textEncodingType == AV_ID3V2_UTF8) {
3208                                                                 pInfo->pCopyright = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3209                                                                 if (pInfo->pCopyright != NULL) {
3210                                                                         memcpy(pInfo->pCopyright, pExtContent, realCpyFrameNum);
3211                                                                         pInfo->pCopyright[realCpyFrameNum] = '\0';
3212                                                                         /*string copy with '\0'*/
3213                                                                         pInfo->copyrightLen = realCpyFrameNum;
3214                                                                         _STRNCPY_EX(pInfo->pCopyright, pExtContent, pInfo->copyrightLen);
3215                                                                 }
3216                                                         } else {
3217                                                                 pInfo->pCopyright = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->copyrightLen);
3218                                                         }
3219
3220                                                         debug_msg(RELEASE, "pInfo->pCopyright returned = (%s), pInfo->copyrightLen(%d)\n", pInfo->pCopyright, pInfo->copyrightLen);
3221                                                         pInfo->tagV2Info.bCopyRightMarked = true;
3222                                                 } else if (strncmp((char *)CompTmp, "TOPE", 4) == 0 && pInfo->tagV2Info.bOriginArtistMarked == false) {
3223                                                         if (textEncodingType == AV_ID3V2_UTF8) {
3224                                                                 pInfo->pOriginArtist = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3225                                                                 if (pInfo->pOriginArtist != NULL) {
3226                                                                         memcpy(pInfo->pOriginArtist, pExtContent, realCpyFrameNum);
3227                                                                         pInfo->pOriginArtist[realCpyFrameNum] = '\0';
3228                                                                         /*string copy with '\0'*/
3229                                                                         pInfo->originartistLen = realCpyFrameNum;
3230                                                                         _STRNCPY_EX(pInfo->pOriginArtist, pExtContent, pInfo->originartistLen);
3231                                                                 }
3232                                                         } else {
3233                                                                 pInfo->pOriginArtist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->originartistLen);
3234                                                         }
3235
3236                                                         debug_msg(RELEASE, "pInfo->pOriginArtist returned = (%s), pInfo->originartistLen(%d)\n", pInfo->pOriginArtist, pInfo->originartistLen);
3237                                                         pInfo->tagV2Info.bOriginArtistMarked = true;
3238                                                 } else if (strncmp((char *)CompTmp, "TCOM", 4) == 0 && pInfo->tagV2Info.bComposerMarked == false) {
3239                                                         if (textEncodingType == AV_ID3V2_UTF8) {
3240                                                                 pInfo->pComposer = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3241                                                                 if (pInfo->pComposer != NULL) {
3242                                                                         memcpy(pInfo->pComposer, pExtContent, realCpyFrameNum);
3243                                                                         pInfo->pComposer[realCpyFrameNum] = '\0';
3244                                                                         /*string copy with '\0'*/
3245                                                                         pInfo->composerLen = realCpyFrameNum;
3246                                                                         _STRNCPY_EX(pInfo->pComposer, pExtContent, pInfo->composerLen);
3247                                                                 }
3248                                                         } else {
3249                                                                 pInfo->pComposer = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->composerLen);
3250                                                         }
3251
3252                                                         debug_msg(RELEASE, "pInfo->pComposer returned = (%s), pInfo->originartistLen(%d)\n", pInfo->pComposer, pInfo->composerLen);
3253                                                         pInfo->tagV2Info.bComposerMarked = true;
3254                                                 } else if (strncmp((char *)CompTmp, "TDRC", 4) == 0 && pInfo->tagV2Info.bRecDateMarked == false) {      /*TYER(year) and TRDA are replaced by the TDRC */
3255                                                         if (textEncodingType == AV_ID3V2_UTF8) {
3256                                                                 pInfo->pRecDate = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3257                                                                 if (pInfo->pRecDate != NULL) {
3258                                                                         memcpy(pInfo->pRecDate, pExtContent, realCpyFrameNum);
3259                                                                         pInfo->pRecDate[realCpyFrameNum] = '\0';
3260                                                                         /*string copy with '\0'*/
3261                                                                         pInfo->recdateLen = realCpyFrameNum;
3262                                                                         _STRNCPY_EX(pInfo->pRecDate, pExtContent, pInfo->recdateLen);
3263                                                                 }
3264                                                         } else {
3265                                                                 pInfo->pRecDate = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->recdateLen);
3266                                                         }
3267
3268                                                         debug_msg(RELEASE, "pInfo->pRecDate returned = (%s), pInfo->recdateLen(%d)\n", pInfo->pRecDate, pInfo->recdateLen);
3269                                                         pInfo->tagV2Info.bRecDateMarked = true;
3270                                                 } else if (strncmp((char *)CompTmp, "TIT1", 4) == 0 && pInfo->tagV2Info.bContentGroupMarked == false) {
3271                                                         if (textEncodingType == AV_ID3V2_UTF8) {
3272                                                                 pInfo->pContentGroup = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3273                                                                 if (pInfo->pContentGroup != NULL) {
3274                                                                         memcpy(pInfo->pContentGroup, pExtContent, realCpyFrameNum);
3275                                                                         pInfo->pContentGroup[realCpyFrameNum] = '\0';
3276                                                                         /*string copy with '\0'*/
3277                                                                         pInfo->contentGroupLen = realCpyFrameNum;
3278                                                                         _STRNCPY_EX(pInfo->pContentGroup, pExtContent, pInfo->contentGroupLen);
3279                                                                 }
3280                                                         } else {
3281                                                                 pInfo->pContentGroup = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->contentGroupLen);
3282                                                         }
3283
3284                                                         debug_msg(RELEASE, "pInfo->pContentGroup returned = (%s), pInfo->contentGroupLen(%d)\n", pInfo->pContentGroup, pInfo->contentGroupLen);
3285                                                         pInfo->tagV2Info.bContentGroupMarked = true;
3286                                                 } else if (strncmp((char *)CompTmp, "APIC", 4) == 0 && pInfo->tagV2Info.bImageMarked == false && realCpyFrameNum <= 2000000) {
3287                                                         if (pExtContent[0] != '\0') {
3288                                                                 for (inx = 0; inx < MP3_ID3_IMAGE_MIME_TYPE_MAX_LENGTH - 1; inx++)
3289                                                                         pInfo->imageInfo.imageMIMEType[inx] = '\0';/*ini mimetype variable */
3290
3291                                                                 while ((checkImgMimeTypeMax < MP3_ID3_IMAGE_MIME_TYPE_MAX_LENGTH - 1) && pExtContent[checkImgMimeTypeMax] != '\0') {
3292                                                                         pInfo->imageInfo.imageMIMEType[checkImgMimeTypeMax] = pExtContent[checkImgMimeTypeMax];
3293                                                                         checkImgMimeTypeMax++;
3294                                                                 }
3295                                                                 pInfo->imageInfo.imgMimetypeLen = checkImgMimeTypeMax;
3296                                                         } else {
3297                                                                 pInfo->imageInfo.imgMimetypeLen = 0;
3298                                                         }
3299
3300                                                         imgstartOffset += checkImgMimeTypeMax;
3301
3302                                                         if (strncmp(pInfo->imageInfo.imageMIMEType, MIME_PRFIX, strlen(MIME_PRFIX)) != 0) {
3303                                                                 pInfo->imageInfo.imgMimetypeLen = 0;
3304                                                                 debug_error(DEBUG, "APIC NOT VALID");
3305                                                                 continue;
3306                                                         }
3307
3308                                                         if ((pExtContent[imgstartOffset] == '\0') && (realCpyFrameNum - imgstartOffset > 0)) {
3309                                                                 imgstartOffset++;/*endofMIME(1byte) */
3310
3311                                                                 if (pExtContent[imgstartOffset] < AV_ID3V2_PICTURE_TYPE_MAX) {
3312                                                                         pInfo->imageInfo.pictureType = pExtContent[imgstartOffset];
3313                                                                 }
3314                                                                 imgstartOffset++;/*PictureType(1byte) */
3315
3316                                                                 if (pExtContent[imgstartOffset] != 0x0) {
3317                                                                         int cur_pos = 0;
3318                                                                         int dis_len = 0;
3319                                                                         int new_dis_len = 0;
3320                                                                         char *tmp_desc = NULL;
3321
3322                                                                         while (1) {
3323                                                                                 if (pExtContent[imgstartOffset + cur_pos] == '\0') {
3324                                                                                         if (realCpyFrameNum < imgstartOffset + cur_pos) {
3325                                                                                                 debug_error(DEBUG, "End of APIC Tag %d %d %d\n", realCpyFrameNum, imgstartOffset, cur_pos);
3326                                                                                                 break;
3327                                                                                         }
3328                                                                                         /*check end of image description*/
3329                                                                                         if ((pExtContent[imgstartOffset + cur_pos + 1] == gTagJPEGHeader[0]) ||
3330                                                                                             (pExtContent[imgstartOffset + cur_pos + 1] == gTagPNGHeader[0])) {
3331                                                                                                 debug_msg(RELEASE, "length of description (%d)", cur_pos);
3332                                                                                                 break;
3333                                                                                         }
3334                                                                                 }
3335                                                                                 cur_pos++;
3336                                                                         }
3337
3338                                                                         dis_len = cur_pos + 1;
3339
3340                                                                         tmp_desc = mmfile_malloc(sizeof(char) * dis_len);
3341
3342                                                                         if (tmp_desc != NULL) {
3343                                                                                 memcpy(tmp_desc, pExtContent + imgstartOffset, dis_len);
3344                                                                                 debug_msg(DEBUG, "tmp_desc %s\n", tmp_desc);
3345
3346                                                                                 /*convert description*/
3347                                                                                 pInfo->imageInfo.imageDescription = mmfile_string_convert(tmp_desc, dis_len, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&new_dis_len);
3348                                                                                 debug_msg(DEBUG, "new_desc %s(%d)\n", pInfo->imageInfo.imageDescription, new_dis_len);
3349                                                                                 mmfile_free(tmp_desc);
3350
3351                                                                                 pInfo->imageInfo.imgDesLen = new_dis_len; /**/
3352                                                                         }
3353
3354                                                                         imgstartOffset += cur_pos;
3355                                                                 } else {
3356                                                                         pInfo->imageInfo.imgDesLen = 0;
3357                                                                 }
3358
3359                                                                 if ((pExtContent[imgstartOffset] == '\0') && (realCpyFrameNum - imgstartOffset > 0)) {
3360                                                                         imgstartOffset++; /* endofDesceriptionType(1byte) */
3361
3362                                                                         while (pExtContent[imgstartOffset] == '\0') {   /*some content has useless '\0' in front of picture data */
3363                                                                                 imgstartOffset++;
3364                                                                         }
3365
3366                                                                         debug_msg(RELEASE, "after scaning imgDescription imgstartOffset(%d) value!\n", imgstartOffset);
3367
3368                                                                         if (realCpyFrameNum - imgstartOffset > 0) {
3369                                                                                 pInfo->imageInfo.imageLen = realCpyFrameNum - imgstartOffset;
3370                                                                                 pInfo->imageInfo.pImageBuf = mmfile_malloc(pInfo->imageInfo.imageLen + 1);
3371
3372                                                                                 if (pInfo->imageInfo.pImageBuf != NULL) {
3373                                                                                         memcpy(pInfo->imageInfo.pImageBuf, pExtContent + imgstartOffset, pInfo->imageInfo.imageLen);
3374                                                                                         pInfo->imageInfo.pImageBuf[pInfo->imageInfo.imageLen] = 0;
3375                                                                                 }
3376
3377                                                                                 if (IS_INCLUDE_URL(pInfo->imageInfo.imageMIMEType))
3378                                                                                         pInfo->imageInfo.bURLInfo = true; /*if mimetype is "-->", image date has an URL */
3379                                                                         } else {
3380                                                                                 debug_msg(RELEASE, "No APIC image!! realCpyFrameNum(%d) - imgstartOffset(%d)\n", realCpyFrameNum, imgstartOffset);
3381                                                                         }
3382                                                                 }
3383                                                         }
3384
3385                                                         checkImgMimeTypeMax = 0;
3386                                                         inx = 0;
3387                                                         imgstartOffset = 0;
3388                                                         pInfo->tagV2Info.bImageMarked = true;
3389                                                 } else {
3390                                                         debug_msg(RELEASE, "CompTmp(%s) This Frame ID currently not Supports!!\n", CompTmp);
3391                                                 }
3392                                         }
3393
3394                                 } else {
3395                                         debug_msg(RELEASE, "mmf_file_id3tag_parse_v224: All of the pExtContent Values are NULL\n");
3396                                 }
3397
3398                         } else {
3399                                 curPos += purelyFramelen;
3400                                 if (purelyFramelen != 0)
3401                                         needToloopv2taglen = MP3_TAGv2_23_TXT_HEADER_LEN;
3402                         }
3403
3404                         if (pExtContent)        _FREE_EX(pExtContent);
3405                         memset(CompTmp, 0, 4);
3406                         if (curPos < taglen) {
3407                                 needToloopv2taglen -= oneFrameLen;
3408                                 v2numOfFrames++;
3409                         } else
3410                                 needToloopv2taglen = MP3_TAGv2_23_TXT_HEADER_LEN;
3411
3412                         oneFrameLen = 0;
3413                         encodingOffSet = 0;
3414                         realCpyFrameNum = 0;
3415                         textEncodingType = 0;
3416                         purelyFramelen = 0;
3417
3418                 }
3419         }
3420
3421         release_characterset_array(charset_array);
3422
3423         if (taglen)
3424                 return true;
3425         else
3426                 return false;
3427
3428 }
3429
3430 EXPORT_API
3431 void mm_file_id3tag_restore_content_info(AvFileContentInfo *pInfo)
3432 {
3433         char    *mpegAudioGenre = NULL/*, *tmpGenreForV1Tag = NULL*/;
3434         bool    bAdditionGenre = false /*, bMpegAudioFrame = false*/;
3435         int mpegAudioFileLen = 0, idv2IntGenre = 148/*, tmpinx = 0, tmpinx2=0*/;
3436 #ifdef _SM_ONLY
3437         char    *pGenreForUTF16;
3438 #endif
3439         unsigned char genre = pInfo->genre;
3440
3441         /* for Genre Info */
3442         if (pInfo->tagV2Info.bGenreMarked == false) {
3443                 if (pInfo->bV1tagFound == true) {
3444                         debug_msg(RELEASE, "Genre: %d\n", genre);
3445
3446                         if (genre > 147)
3447                                 genre = 148;
3448
3449                         if (MpegAudio_Genre[genre] != NULL) {
3450                                 pInfo->genreLen = strlen(MpegAudio_Genre[genre]);
3451                                 if (pInfo->genreLen > 0) {
3452                                         /* Give space for NULL character. Hence added "+1" */
3453                                         pInfo->pGenre = mmfile_malloc(sizeof(char) * (pInfo->genreLen + 1));
3454                                         if (pInfo->pGenre) {
3455                                                 strncpy(pInfo->pGenre, MpegAudio_Genre[genre], pInfo->genreLen);
3456                                                 pInfo->pGenre[pInfo->genreLen] = '\0';
3457                                         }
3458                                 }
3459                         }
3460                 } else {
3461                         debug_msg(RELEASE, "Genre was not Found.\n");
3462                 }
3463         } else if (pInfo->tagV2Info.bGenreMarked == true) {
3464                 if (pInfo->genreLen && pInfo->tagV2Info.bGenreUTF16) {
3465                         pInfo->pGenre[pInfo->genreLen + 1] = '\0';
3466                         mpegAudioGenre = mmfile_malloc(sizeof(char) * (pInfo->genreLen * AV_WM_LOCALCODE_SIZE_MAX + 1));
3467 #ifdef _SM_ONLY
3468                         pGenreForUTF16 = (char *)pInfo->pGenre;
3469
3470                         if (WmConvert2LCode(mpegAudioGenre, sizeof(char) * AV_WM_LOCALCODE_SIZE_MAX * (pInfo->genreLen + 1), pGenreForUTF16)) {
3471                                 pInfo->genreLen = strlen(mpegAudioGenre);
3472                                 mpegAudioGenre[pInfo->genreLen] = '\0';
3473                         }
3474 #endif
3475                 } else {
3476                         debug_msg(RELEASE, "pInfo->genreLen size is Zero Or not UTF16 code! genreLen[%d] genre[%s]\n", pInfo->genreLen, pInfo->pGenre);
3477
3478                         if (pInfo->pGenre) {
3479                                 pInfo->genreLen = strlen(pInfo->pGenre);
3480                                 mpegAudioGenre = mmfile_malloc(sizeof(char) * (pInfo->genreLen + 1));
3481                                 if (mpegAudioGenre != NULL) {
3482                                         mpegAudioGenre[pInfo->genreLen] = '\0';
3483                                         strncpy(mpegAudioGenre, pInfo->pGenre, pInfo->genreLen);
3484                                 }
3485                         } else {
3486                                 pInfo->genreLen = 0;
3487                         }
3488                 }
3489
3490                 if (pInfo->pGenre) _FREE_EX(pInfo->pGenre);
3491
3492                 /*tmpinx = 0;*/
3493                 if (mpegAudioGenre != NULL) {
3494                         /**
3495                          *Genre number
3496                          * (XXX)        XXX is 0 - 148
3497                          */
3498                         pInfo->genreLen = strlen(mpegAudioGenre);
3499                         if (pInfo->genreLen >= 3 &&
3500                             mpegAudioGenre[0] == '(' && mpegAudioGenre[pInfo->genreLen - 1] == ')') {
3501                                 bAdditionGenre = true;
3502                                 for (mpegAudioFileLen = 1; mpegAudioFileLen <= pInfo->genreLen - 2; mpegAudioFileLen++) {
3503                                         if (mpegAudioGenre[mpegAudioFileLen] < '0' || mpegAudioGenre[mpegAudioFileLen] > '9') {
3504                                                 bAdditionGenre = false;
3505                                                 break;
3506                                         }
3507                                 }
3508                         }
3509
3510                         if (bAdditionGenre == true) {
3511                                 idv2IntGenre = atoi(mpegAudioGenre + 1);
3512
3513                                 if (idv2IntGenre > 147 || idv2IntGenre < 0)
3514                                         idv2IntGenre = 148;
3515
3516                                 if (MpegAudio_Genre[idv2IntGenre] != NULL) {
3517                                         pInfo->genreLen = strlen(MpegAudio_Genre[idv2IntGenre]);
3518                                         if (pInfo->genreLen > 0) {
3519                                                 /* Give space for NULL character. Hence added "+1" */
3520                                                 pInfo->pGenre = mmfile_malloc(sizeof(char) * (pInfo->genreLen + 1));
3521                                                 if (pInfo->pGenre) {
3522                                                         strncpy(pInfo->pGenre, MpegAudio_Genre[idv2IntGenre], pInfo->genreLen);
3523                                                         pInfo->pGenre[pInfo->genreLen] = 0;
3524                                                 }
3525                                         }
3526                                 }
3527                                 debug_msg(RELEASE, "pInfo->pGenre = %s\n", pInfo->pGenre);
3528                         } else if (bAdditionGenre == false && pInfo->genreLen > 0) {
3529                                 /**
3530                                  * Genre string.
3531                                  */
3532
3533                                 /* Give space for NULL character. Hence added "+1" */
3534                                 pInfo->pGenre = mmfile_malloc(sizeof(char) * (pInfo->genreLen + 1));
3535                                 if (pInfo->pGenre) {
3536                                         strncpy(pInfo->pGenre, mpegAudioGenre, pInfo->genreLen);
3537                                         pInfo->pGenre[pInfo->genreLen] = '\0';
3538                                 }
3539                                 debug_msg(RELEASE, "pInfo->pGenre = %s, pInfo->genreLen = %d\n", pInfo->pGenre, pInfo->genreLen);
3540                         } else {
3541                                 debug_msg(RELEASE, "Failed to \"(...)\" value to genre = %s\n", pInfo->pGenre);
3542                         }
3543                 } else {
3544                         debug_msg(RELEASE, "mpegAudioGenre = %s\n", mpegAudioGenre);
3545                 }
3546                 if (mpegAudioGenre)
3547                         _FREE_EX(mpegAudioGenre);
3548
3549         } else {
3550                 debug_msg(RELEASE, "Neither ID3 v1 nor v2 info doesn't have Genre Info.\n");
3551         }
3552
3553 }
3554
3555 void mm_file_free_synclyrics_list(GList *synclyrics_list)
3556 {
3557         int list_len = 0;
3558         int idx = 0;
3559         AvSynclyricsInfo *synclyrics_info = NULL;
3560
3561         if (synclyrics_list == NULL) {
3562                 return;
3563         }
3564
3565         list_len = g_list_length(synclyrics_list);
3566         for (idx = 0; idx < list_len; idx++) {
3567                 synclyrics_info = g_list_nth_data(synclyrics_list, idx);
3568
3569                 if (synclyrics_info != NULL) {
3570                         mmfile_free(synclyrics_info->lyric_info);
3571                         mmfile_free(synclyrics_info);
3572                 }
3573         }
3574
3575         if (synclyrics_list != NULL) {
3576                 g_list_free(synclyrics_list);
3577                 synclyrics_list = NULL;
3578         }
3579
3580         return;
3581 }
3582