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