Fix null pointer dereferenced issue (WGID-28322)
[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                                 if (textEncodingType > AV_ID3V2_MAX) {
1797                                         debug_msg("WRONG ENCOIDNG TYPE [%d], FRAME[%s]\n", textEncodingType, (char *)CompTmp);
1798                                         continue;
1799                                 }
1800
1801                                 /*in order to deliver valid string to MP */
1802                                 while ((buffer[curPos - purelyFramelen + encodingOffSet] < 0x20) && (encodingOffSet < purelyFramelen))
1803                                         encodingOffSet++;
1804
1805                                 if (encodingOffSet < purelyFramelen) {
1806                                         realCpyFrameNum = purelyFramelen - encodingOffSet;
1807                                         pExtContent = mmfile_malloc(realCpyFrameNum + 3);
1808
1809                                         if (pExtContent == NULL) {
1810                                                 debug_error("out of memory for pExtContent\n");
1811                                                 continue;
1812                                         }
1813
1814                                         memset(pExtContent, '\0', realCpyFrameNum + 3);
1815
1816                                         memcpy(pExtContent, &buffer[curPos - purelyFramelen + encodingOffSet], purelyFramelen - encodingOffSet);
1817
1818                                         if (realCpyFrameNum > 0) {
1819                                                 if (strncmp((char *)CompTmp, "TT2", 3) == 0 && pInfo->tagV2Info.bTitleMarked == false) {
1820                                                         pInfo->pTitle = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->titleLen);
1821
1822 #ifdef __MMFILE_TEST_MODE__
1823                                                         debug_msg("pInfo->pTitle returned = (%s), pInfo->titleLen(%d)\n", pInfo->pTitle, pInfo->titleLen);
1824 #endif
1825                                                         pInfo->tagV2Info.bTitleMarked = true;
1826                                                 } else if (strncmp((char *)CompTmp, "TP1", 3) == 0 && pInfo->tagV2Info.bArtistMarked == false) {
1827                                                         pInfo->pArtist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->artistLen);
1828
1829 #ifdef __MMFILE_TEST_MODE__
1830                                                         debug_msg("pInfo->pArtist returned = (%s), pInfo->artistLen(%d)\n", pInfo->pArtist, pInfo->artistLen);
1831 #endif
1832                                                         pInfo->tagV2Info.bArtistMarked = true;
1833                                                 } else if (strncmp((char *)CompTmp, "TP2", 3) == 0 && pInfo->tagV2Info.bAlbum_ArtistMarked == false) {
1834                                                         pInfo->pAlbum_Artist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->album_artistLen);
1835
1836 #ifdef __MMFILE_TEST_MODE__
1837                                                         debug_msg("pInfo->pAlbum_Artist returned = (%s), pInfo->album_artistLen(%d)\n", pInfo->pAlbum_Artist, pInfo->album_artistLen);
1838 #endif
1839                                                         pInfo->tagV2Info.bAlbum_ArtistMarked = true;
1840                                                 } else if (strncmp((char *)CompTmp, "TP3", 3) == 0 && pInfo->tagV2Info.bConductorMarked == false) {
1841                                                         pInfo->pConductor = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->conductorLen);
1842
1843 #ifdef __MMFILE_TEST_MODE__
1844                                                         debug_msg("pInfo->pConductor returned = (%s), pInfo->conductorLen(%d)\n", pInfo->pConductor, pInfo->conductorLen);
1845 #endif
1846                                                         pInfo->tagV2Info.bConductorMarked = true;
1847                                                 } else if (strncmp((char *)CompTmp, "TAL", 3) == 0 && pInfo->tagV2Info.bAlbumMarked == false) {
1848                                                         pInfo->pAlbum = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->albumLen);
1849
1850 #ifdef __MMFILE_TEST_MODE__
1851                                                         debug_msg("pInfo->pAlbum returned = (%s), pInfo->albumLen(%d)\n", pInfo->pAlbum, pInfo->albumLen);
1852 #endif
1853                                                         pInfo->tagV2Info.bAlbumMarked = true;
1854                                                 } else if (strncmp((char *)CompTmp, "TYE", 3) == 0 && pInfo->tagV2Info.bYearMarked == false) {
1855                                                         pInfo->pYear = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->yearLen);
1856
1857 #ifdef __MMFILE_TEST_MODE__
1858                                                         debug_msg("pInfo->pYear returned = (%s), pInfo->yearLen(%d)\n", pInfo->pYear, pInfo->yearLen);
1859 #endif
1860                                                         pInfo->tagV2Info.bYearMarked = true;
1861                                                 } else if (strncmp((char *)CompTmp, "COM", 3) == 0 && pInfo->tagV2Info.bDescriptionMarked == false) {
1862                                                         /*skip language data! */
1863                                                         if (realCpyFrameNum > 4) {
1864                                                                 realCpyFrameNum -= 4;
1865                                                                 tmp = 4;
1866
1867                                                                 /*pExtContent[tmp+1] value should't have encoding value */
1868                                                                 if (pExtContent[tmp] > 0x20 && (pExtContent[tmp - 1] == 0x00 || pExtContent[tmp - 1] == 0x01)) {
1869                                                                         if (pExtContent[tmp - 1] == 0x00)
1870                                                                                 textEncodingType = AV_ID3V2_ISO_8859;
1871                                                                         else
1872                                                                                 textEncodingType = AV_ID3V2_UTF16;
1873
1874                                                                         pInfo->pComment = mmfile_string_convert((char *)&pExtContent[tmp], realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->commentLen);
1875
1876 #ifdef __MMFILE_TEST_MODE__
1877                                                                         debug_msg("pInfo->pComment returned = (%s), pInfo->commentLen(%d)\n", pInfo->pComment, pInfo->commentLen);
1878 #endif
1879                                                                         pInfo->tagV2Info.bDescriptionMarked = true;
1880                                                                 } else {
1881 #ifdef __MMFILE_TEST_MODE__
1882                                                                         debug_msg("mmf_file_id3tag_parse_v222: failed to get Comment Info tmp(%d), purelyFramelen - encodingOffSet(%d)\n", tmp, purelyFramelen - encodingOffSet);
1883 #endif
1884                                                                 }
1885                                                         } else {
1886 #ifdef __MMFILE_TEST_MODE__
1887                                                                 debug_msg("mmf_file_id3tag_parse_v222: Description info too small to parse realCpyFrameNum(%d)\n", realCpyFrameNum);
1888 #endif
1889                                                         }
1890                                                         tmp = 0;
1891
1892                                                 } else if (strncmp((char *)CompTmp, "TCO", 3) == 0 && pInfo->tagV2Info.bGenreMarked == false) {
1893                                                         pInfo->pGenre = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->genreLen);
1894
1895 #ifdef __MMFILE_TEST_MODE__
1896                                                         debug_msg("pInfo->pGenre returned = (%s), pInfo->genreLen(%d)\n", pInfo->pGenre, pInfo->genreLen);
1897 #endif
1898
1899                                                         if ((pInfo->pGenre != NULL) && (pInfo->genreLen > 0)) {
1900                                                                 bool ret = FALSE;
1901                                                                 int int_genre = -1;
1902
1903                                                                 ret = is_numeric(pInfo->pGenre, pInfo->genreLen);
1904
1905                                                                 if (ret == TRUE) {
1906                                                                         sscanf(pInfo->pGenre, "%d", &int_genre);
1907 #ifdef __MMFILE_TEST_MODE__
1908                                                                         debug_msg("genre information is inteager [%d]\n", int_genre);
1909 #endif
1910
1911                                                                         /*Change int to string */
1912                                                                         if ((0 <= int_genre) && (int_genre < GENRE_COUNT - 1)) {
1913                                                                                 /*save genreinfo like "(123)". mm_file_id3tag_restore_content_info convert it to string*/
1914                                                                                 char tmp_genre[6] = {0, };      /*ex. "(123)+NULL"*/
1915                                                                                 int tmp_genre_len = 0;
1916
1917                                                                                 memset(tmp_genre, 0, 6);
1918                                                                                 snprintf(tmp_genre, sizeof(tmp_genre), "(%d)", int_genre);
1919
1920                                                                                 tmp_genre_len = strlen(tmp_genre);
1921                                                                                 if (tmp_genre_len > 0) {
1922                                                                                         if (pInfo->pGenre) _FREE_EX(pInfo->pGenre);
1923                                                                                         pInfo->pGenre = mmfile_malloc(sizeof(char) * (tmp_genre_len + 1));
1924                                                                                         if (pInfo->pGenre) {
1925                                                                                                 strncpy(pInfo->pGenre, tmp_genre, tmp_genre_len);
1926                                                                                                 pInfo->pGenre[tmp_genre_len] = 0;
1927                                                                                         }
1928                                                                                 }
1929                                                                         }
1930                                                                 }
1931                                                         }
1932
1933                                                         pInfo->tagV2Info.bGenreMarked = true;
1934                                                 } else if (strncmp((char *)CompTmp, "TRK", 3) == 0 && pInfo->tagV2Info.bTrackNumMarked == false) {
1935                                                         pInfo->pTrackNum = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->tracknumLen);
1936
1937 #ifdef __MMFILE_TEST_MODE__
1938                                                         debug_msg("pInfo->pTrackNum returned = (%s), pInfo->tracknumLen(%d)\n", pInfo->pTrackNum, pInfo->tracknumLen);
1939 #endif
1940                                                         pInfo->tagV2Info.bTrackNumMarked = true;
1941                                                 } else if (strncmp((char *)CompTmp, "TEN", 3) == 0 && pInfo->tagV2Info.bEncByMarked == false) {
1942                                                         pInfo->pEncBy = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->encbyLen);
1943
1944 #ifdef __MMFILE_TEST_MODE__
1945                                                         debug_msg("pInfo->pEncBy returned = (%s), pInfo->encbyLen(%d)\n", pInfo->pEncBy, pInfo->encbyLen);
1946 #endif
1947                                                         pInfo->tagV2Info.bEncByMarked = true;
1948                                                 } else if (strncmp((char *)CompTmp, "WXX", 3) == 0 && pInfo->tagV2Info.bURLMarked == false) {
1949                                                         if (realCpyFrameNum > 4) {
1950                                                                 /*skip language data! */
1951                                                                 realCpyFrameNum -= 4;
1952                                                                 tmp = 4;
1953
1954                                                                 /*pExtContent[tmp+1] value should't have null value */
1955                                                                 if (pExtContent[tmp] > 0x20 && (pExtContent[tmp - 1] == 0x00 || pExtContent[tmp - 1] == 0x01)) {
1956                                                                         if (pExtContent[tmp - 1] == 0x00)
1957                                                                                 textEncodingType = AV_ID3V2_ISO_8859;
1958                                                                         else
1959                                                                                 textEncodingType = AV_ID3V2_UTF16;
1960
1961                                                                         pInfo->pURL = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->urlLen);
1962
1963 #ifdef __MMFILE_TEST_MODE__
1964                                                                         debug_msg("pInfo->pURL returned = (%s), pInfo->urlLen(%d)\n", pInfo->pURL, pInfo->urlLen);
1965 #endif
1966                                                                         pInfo->tagV2Info.bURLMarked = true;
1967                                                                 } else {
1968 #ifdef __MMFILE_TEST_MODE__
1969                                                                         debug_msg("mmf_file_id3tag_parse_v222: failed to get URL Info tmp(%d), purelyFramelen - encodingOffSet(%d)\n", tmp, purelyFramelen - encodingOffSet);
1970 #endif
1971                                                                 }
1972                                                         } else {
1973 #ifdef __MMFILE_TEST_MODE__
1974                                                                 debug_msg("mmf_file_id3tag_parse_v222: URL info too small to parse realCpyFrameNum(%d)\n", realCpyFrameNum);
1975 #endif
1976                                                         }
1977                                                         tmp = 0;
1978                                                 } else if (strncmp((char *)CompTmp, "TCR", 3) == 0 && pInfo->tagV2Info.bCopyRightMarked == false) {
1979                                                         pInfo->pCopyright = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->copyrightLen);
1980
1981 #ifdef __MMFILE_TEST_MODE__
1982                                                         debug_msg("pInfo->pCopyright returned = (%s), pInfo->copyrightLen(%d)\n", pInfo->pCopyright, pInfo->copyrightLen);
1983 #endif
1984                                                         pInfo->tagV2Info.bCopyRightMarked = true;
1985                                                 } else if (strncmp((char *)CompTmp, "TOA", 3) == 0 && pInfo->tagV2Info.bOriginArtistMarked == false) {
1986                                                         pInfo->pOriginArtist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->originartistLen);
1987
1988 #ifdef __MMFILE_TEST_MODE__
1989                                                         debug_msg("pInfo->pOriginArtist returned = (%s), pInfo->originartistLen(%d)\n", pInfo->pOriginArtist, pInfo->originartistLen);
1990 #endif
1991                                                         pInfo->tagV2Info.bOriginArtistMarked = true;
1992                                                 } else if (strncmp((char *)CompTmp, "TCM", 3) == 0 && pInfo->tagV2Info.bComposerMarked == false) {
1993                                                         pInfo->pComposer = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->composerLen);
1994
1995 #ifdef __MMFILE_TEST_MODE__
1996                                                         debug_msg("pInfo->pComposer returned = (%s), pInfo->originartistLen(%d)\n", pInfo->pComposer, pInfo->composerLen);
1997 #endif
1998                                                         pInfo->tagV2Info.bComposerMarked = true;
1999                                                 } else if (strncmp((char *)CompTmp, "TRD", 3) == 0 && pInfo->tagV2Info.bRecDateMarked == false) {
2000                                                         pInfo->pRecDate = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->recdateLen);
2001
2002 #ifdef __MMFILE_TEST_MODE__
2003                                                         debug_msg("pInfo->pRecDate returned = (%s), pInfo->recdateLen(%d)\n", pInfo->pRecDate, pInfo->recdateLen);
2004 #endif
2005                                                         pInfo->tagV2Info.bRecDateMarked = true;
2006                                                 } else if (strncmp((char *)CompTmp, "PIC", 3) == 0 && pInfo->tagV2Info.bImageMarked == false && realCpyFrameNum <= 2000000) {
2007                                                         if (pExtContent[0] != 0) {
2008                                                                 for (inx = 0; inx < MP3_ID3_IMAGE_EXT_MAX_LENGTH; inx++)
2009                                                                         pInfo->imageInfo.imageExt[inx] = '\0';/*ini mimetype variable */
2010
2011                                                                 while ((checkImgExtMax < MP3_ID3_IMAGE_EXT_MAX_LENGTH - 1) && pExtContent[checkImgExtMax] != '\0') {
2012                                                                         pInfo->imageInfo.imageExt[checkImgExtMax] = pExtContent[checkImgExtMax];
2013                                                                         checkImgExtMax++;
2014                                                                 }
2015                                                         } else {
2016 #ifdef __MMFILE_TEST_MODE__
2017                                                                 debug_msg("mmf_file_id3tag_parse_v222: PIC image's not included to image Extention\n");
2018 #endif
2019                                                         }
2020
2021                                                         imgstartOffset += checkImgExtMax;
2022
2023                                                         if (pExtContent[imgstartOffset] < AV_ID3V2_PICTURE_TYPE_MAX) {
2024                                                                 pInfo->imageInfo.pictureType = pExtContent[imgstartOffset];
2025                                                         }
2026                                                         imgstartOffset++;/*PictureType(1byte) */
2027
2028                                                         if (pExtContent[imgstartOffset] != 0x0) {
2029                                                                 int cur_pos = 0;
2030                                                                 int dis_len = 0;
2031                                                                 int new_dis_len = 0;
2032                                                                 char *tmp_desc = NULL;
2033
2034                                                                 while (1) {
2035                                                                         if (pExtContent[imgstartOffset + cur_pos] == '\0') {
2036                                                                                 if (realCpyFrameNum < imgstartOffset + cur_pos) {
2037                                                                                         debug_error("End of APIC Tag %d %d %d\n", realCpyFrameNum, imgstartOffset, cur_pos);
2038                                                                                         break;
2039                                                                                 }
2040                                                                                 /*check end of image description*/
2041                                                                                 if ((pExtContent[imgstartOffset + cur_pos + 1] == gTagJPEGHeader[0]) ||
2042                                                                                     (pExtContent[imgstartOffset + cur_pos + 1] == gTagPNGHeader[0])) {
2043 #ifdef __MMFILE_TEST_MODE__
2044                                                                                         debug_msg("length of description (%d)", cur_pos);
2045 #endif
2046
2047                                                                                         break;
2048                                                                                 }
2049                                                                         }
2050                                                                         cur_pos++;
2051                                                                 }
2052
2053                                                                 dis_len = cur_pos + 1;
2054
2055                                                                 tmp_desc = mmfile_malloc(sizeof(char) * dis_len);
2056
2057                                                                 if (tmp_desc != NULL) {
2058                                                                         memcpy(tmp_desc, pExtContent + imgstartOffset, dis_len);
2059
2060                                                                         /*convert description*/
2061                                                                         pInfo->imageInfo.imageDescription = mmfile_string_convert(tmp_desc, dis_len, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&new_dis_len);
2062                                                                         mmfile_free(tmp_desc);
2063
2064 #ifdef __MMFILE_TEST_MODE__
2065                                                                         debug_msg("new_desc %s(%d)\n", pInfo->imageInfo.imageDescription, new_dis_len);
2066 #endif
2067                                                                         pInfo->imageInfo.imgDesLen = new_dis_len; /**/
2068                                                                 }
2069
2070                                                                 imgstartOffset += cur_pos;
2071                                                         } else {
2072                                                                 pInfo->imageInfo.imgDesLen = 0;
2073                                                         }
2074
2075                                                         if ((pExtContent[imgstartOffset] == '\0') && (realCpyFrameNum - imgstartOffset > 0)) {
2076                                                                 imgstartOffset++; /* endofDesceriptionType(1byte) */
2077
2078                                                                 while (pExtContent[imgstartOffset] == '\0') {   /*some content has useless '\0' in front of picture data */
2079                                                                         imgstartOffset++;
2080                                                                 }
2081
2082 #ifdef __MMFILE_TEST_MODE__
2083                                                                 debug_msg("after scaning imgDescription imgstartOffset(%d) value!\n", imgstartOffset);
2084 #endif
2085
2086                                                                 if (realCpyFrameNum - imgstartOffset > 0) {
2087                                                                         pInfo->imageInfo.imageLen = realCpyFrameNum - imgstartOffset;
2088                                                                         pInfo->imageInfo.pImageBuf = mmfile_malloc(pInfo->imageInfo.imageLen + 1);
2089
2090                                                                         if (pInfo->imageInfo.pImageBuf != NULL) {
2091                                                                                 memcpy(pInfo->imageInfo.pImageBuf, pExtContent + imgstartOffset, pInfo->imageInfo.imageLen);
2092                                                                                 pInfo->imageInfo.pImageBuf[pInfo->imageInfo.imageLen] = 0;
2093                                                                         }
2094
2095                                                                         if (IS_INCLUDE_URL(pInfo->imageInfo.imageMIMEType))
2096                                                                                 pInfo->imageInfo.bURLInfo = true; /*if mimetype is "-->", image date has an URL */
2097                                                                 } else {
2098 #ifdef __MMFILE_TEST_MODE__
2099                                                                         debug_msg("No APIC image!! realCpyFrameNum(%d) - imgstartOffset(%d)\n", realCpyFrameNum, imgstartOffset);
2100 #endif
2101                                                                 }
2102                                                         }
2103
2104                                                         /*checkImgMimeTypeMax = 0;*/
2105                                                         checkImgExtMax = 0;
2106                                                         inx = 0;
2107                                                         imgstartOffset = 0;
2108                                                         pInfo->tagV2Info.bImageMarked = true;
2109
2110                                                 }
2111                                         }
2112
2113                                 }
2114                         } else {
2115                                 curPos += purelyFramelen;
2116                                 if (purelyFramelen != 0)
2117                                         needToloopv2taglen = MP3_TAGv2_22_TXT_HEADER_LEN;
2118                         }
2119
2120                         if (pExtContent)        _FREE_EX(pExtContent);
2121                         memset(CompTmp, 0, 4);
2122                         if (curPos < taglen) {
2123                                 needToloopv2taglen -= oneFrameLen;
2124                                 v2numOfFrames++;
2125                         } else
2126                                 needToloopv2taglen = MP3_TAGv2_22_TXT_HEADER_LEN;
2127                         oneFrameLen = 0;
2128                         encodingOffSet = 0;
2129                         realCpyFrameNum = 0;
2130                         textEncodingType = 0;
2131                         purelyFramelen = 0;
2132
2133                 }
2134         }
2135
2136         release_characterset_array(charset_array);
2137
2138         if (taglen) {
2139                 return true;
2140         } else {
2141                 return false;
2142         }
2143 }
2144
2145 EXPORT_API
2146 bool mm_file_id3tag_parse_v223(AvFileContentInfo *pInfo, unsigned char *buffer)
2147 {
2148         unsigned long taglen = 0;
2149         unsigned long needToloopv2taglen;
2150         unsigned long oneFrameLen = 0;
2151         unsigned long v2numOfFrames = 0;
2152         unsigned long curPos = 0;
2153         char CompTmp[5];
2154         unsigned char *pExtContent = NULL;
2155         unsigned long purelyFramelen = 0;
2156         unsigned int encodingOffSet = 0;
2157         int inx = 0, realCpyFrameNum = 0, checkImgMimeTypeMax = 0, imgstartOffset = 0,  tmp = 0;
2158         int textEncodingType = 0;
2159         char **charset_array = NULL;
2160         const char *MIME_PRFIX = "image/";
2161
2162         make_characterset_array(&charset_array);
2163
2164         init_content_info(pInfo);
2165
2166         taglen = pInfo->tagV2Info.tagLen;
2167         needToloopv2taglen = taglen - MP3_TAGv2_HEADER_LEN;
2168         curPos = MP3_TAGv2_HEADER_LEN;
2169
2170 #ifdef __MMFILE_TEST_MODE__
2171         debug_msg("ID3tag v223--------------------------------------------------------------\n");
2172 #endif
2173
2174         /* check Extended Header */
2175         if (buffer[5] & 0x40) {
2176                 /* if extended header exists, skip it*/
2177                 int extendedHeaderLen = (unsigned long)buffer[10] << 21 | (unsigned long)buffer[11] << 14 | (unsigned long)buffer[12] << 7  | (unsigned long)buffer[13];
2178
2179 #ifdef __MMFILE_TEST_MODE__
2180                 debug_msg("--------------- extendedHeaderLen = %d\n", extendedHeaderLen);
2181 #endif
2182
2183                 if (extendedHeaderLen > (int)(taglen - curPos)) {
2184                         debug_error("extended header too long.\n");
2185                 } else {
2186                         curPos += extendedHeaderLen;
2187                         curPos += 4;
2188                 }
2189         }
2190
2191         if (needToloopv2taglen - MP3_TAGv2_23_TXT_HEADER_LEN > MP3_TAGv2_23_TXT_HEADER_LEN) {
2192                 v2numOfFrames = 1;
2193                 while (needToloopv2taglen > MP3_TAGv2_23_TXT_HEADER_LEN) {
2194                         if ((buffer[curPos] < '0' || buffer[curPos] > 'Z') || (buffer[curPos + 1] < '0' || buffer[curPos + 1] > 'Z')
2195                             || (buffer[curPos + 2] < '0' || buffer[curPos + 2] > 'Z') || (buffer[curPos + 3] < '0' || buffer[curPos + 3] > 'Z'))
2196                                 break;
2197
2198                         memcpy(CompTmp, &buffer[curPos], 4);
2199
2200                         CompTmp[4] = 0;
2201                         oneFrameLen = MP3_TAGv2_23_TXT_HEADER_LEN;
2202                         oneFrameLen += (unsigned long)buffer[4 + curPos] << 24 | (unsigned long)buffer[5 + curPos] << 16
2203                                                 | (unsigned long)buffer[6 + curPos] << 8 | (unsigned long)buffer[7 + curPos];
2204
2205 #ifdef __MMFILE_TEST_MODE__
2206                         debug_msg("----------------------------------------------------------------------------------------------------\n");
2207 #endif
2208
2209                         if (oneFrameLen > taglen - curPos)
2210                                 break;
2211
2212                         purelyFramelen = oneFrameLen - MP3_TAGv2_23_TXT_HEADER_LEN;
2213                         curPos += MP3_TAGv2_23_TXT_HEADER_LEN;
2214
2215                         if (oneFrameLen > MP3_TAGv2_23_TXT_HEADER_LEN && purelyFramelen <= taglen - curPos) {
2216                                 curPos += purelyFramelen;
2217
2218                                 if (IS_ENCODEDBY_UTF16(buffer + (curPos - purelyFramelen))) {
2219                                         encodingOffSet = 2;
2220 #ifdef __MMFILE_TEST_MODE__
2221                                         debug_msg("this text string(%s) encoded by UTF16 encodingOffSet(%d)\n", CompTmp, encodingOffSet);
2222 #endif
2223                                         textEncodingType = AV_ID3V2_UTF16;
2224                                 } else if (IS_ENCODEDBY_UTF16_R(buffer + (curPos - purelyFramelen))) {
2225                                         encodingOffSet = 2;
2226 #ifdef __MMFILE_TEST_MODE__
2227                                         debug_msg("this text string(%s) encoded by UTF16 encodingOffSet(%d)\n", CompTmp, encodingOffSet);
2228 #endif
2229                                         textEncodingType = AV_ID3V2_UTF16_BE;
2230                                 } else if (IS_ENCODEDBY_UTF16(buffer + (curPos - purelyFramelen + 1))) {
2231                                         encodingOffSet = 3;
2232 #ifdef __MMFILE_TEST_MODE__
2233                                         debug_msg("this text string(%s) encoded by UTF16 encodingOffSet(%d)\n", CompTmp, encodingOffSet);
2234 #endif
2235                                         textEncodingType = AV_ID3V2_UTF16;
2236                                 } else if (IS_ENCODEDBY_UTF16_R(buffer + (curPos - purelyFramelen + 1))) {
2237                                         encodingOffSet = 3;
2238 #ifdef __MMFILE_TEST_MODE__
2239                                         debug_msg("this text string(%s) encoded by UTF16 encodingOffSet(%d)\n", CompTmp, encodingOffSet);
2240 #endif
2241                                         textEncodingType = AV_ID3V2_UTF16_BE;
2242                                 } else {
2243                                         if (buffer[curPos - purelyFramelen + encodingOffSet] == 0x00) {
2244 #ifdef __MMFILE_TEST_MODE__
2245                                                 debug_msg("encodingOffset will be set to 1\n");
2246 #endif
2247
2248                                                 encodingOffSet = 1;
2249                                         } else {
2250 #ifdef __MMFILE_TEST_MODE__
2251                                                 debug_msg("Finding encodingOffset\n");
2252 #endif
2253
2254                                                 while ((buffer[curPos - purelyFramelen + encodingOffSet] < 0x20) && (encodingOffSet < purelyFramelen)) /* text string encoded by ISO-8859-1 */
2255                                                         encodingOffSet++;
2256                                         }
2257                                         textEncodingType = AV_ID3V2_ISO_8859;
2258 #ifdef __MMFILE_TEST_MODE__
2259                                         debug_msg("this text string(%s) encoded by ISO-8859-1 encodingOffSet(%d)\n", CompTmp, encodingOffSet);
2260 #endif
2261                                 }
2262
2263                                 if (encodingOffSet < purelyFramelen) {
2264                                         realCpyFrameNum = purelyFramelen - encodingOffSet;
2265                                         pExtContent = mmfile_malloc(realCpyFrameNum + 3);
2266
2267                                         if (pExtContent == NULL) {
2268                                                 debug_msg("pExtContent malloc failed\n");
2269                                                 continue;
2270                                         }
2271
2272                                         memset(pExtContent, '\0', realCpyFrameNum + 3);
2273
2274                                         if (textEncodingType != AV_ID3V2_UTF16 && textEncodingType != AV_ID3V2_UTF16_BE) {
2275                                                 if (CompTmp[0] == 'T' || (strcmp(CompTmp, "APIC") == 0)) {
2276 #ifdef __MMFILE_TEST_MODE__
2277                                                         debug_msg("get the new text ecoding type\n");
2278 #endif
2279                                                         textEncodingType = buffer[curPos - purelyFramelen + encodingOffSet - 1];
2280                                                 }
2281                                         }
2282
2283                                         if (textEncodingType > AV_ID3V2_MAX) {
2284                                                 debug_msg("WRONG ENCOIDNG TYPE [%d], FRAME[%s]\n", textEncodingType, (char *)CompTmp);
2285                                                 continue;
2286                                         }
2287
2288                                         memcpy(pExtContent, &buffer[curPos - purelyFramelen + encodingOffSet], purelyFramelen - encodingOffSet);
2289                                         if (realCpyFrameNum > 0) {
2290                                                 if (strncmp((char *)CompTmp, "TIT2", 4) == 0 && pInfo->tagV2Info.bTitleMarked == false) {
2291                                                         pInfo->pTitle = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->titleLen);
2292
2293 #ifdef __MMFILE_TEST_MODE__
2294                                                         debug_msg("pInfo->pTitle returned = (%s), pInfo->titleLen(%d)\n", pInfo->pTitle, pInfo->titleLen);
2295 #endif
2296                                                         pInfo->tagV2Info.bTitleMarked = true;
2297
2298                                                 } else if (strncmp((char *)CompTmp, "TPE1", 4) == 0 && pInfo->tagV2Info.bArtistMarked == false) {
2299                                                         pInfo->pArtist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->artistLen);
2300
2301 #ifdef __MMFILE_TEST_MODE__
2302                                                         debug_msg("pInfo->pArtist returned = (%s), pInfo->artistLen(%d)\n", pInfo->pArtist, pInfo->artistLen);
2303 #endif
2304                                                         pInfo->tagV2Info.bArtistMarked = true;
2305                                                 } else if (strncmp((char *)CompTmp, "TPE2", 4) == 0 && pInfo->tagV2Info.bAlbum_ArtistMarked == false) {
2306                                                         pInfo->pAlbum_Artist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->album_artistLen);
2307
2308 #ifdef __MMFILE_TEST_MODE__
2309                                                         debug_msg("pInfo->pAlbum_Artist returned = (%s), pInfo->album_artistLen(%d)\n", pInfo->pAlbum_Artist, pInfo->album_artistLen);
2310 #endif
2311                                                         pInfo->tagV2Info.bAlbum_ArtistMarked = true;
2312                                                 } else if (strncmp((char *)CompTmp, "TPE3", 4) == 0 && pInfo->tagV2Info.bConductorMarked == false) {
2313                                                         pInfo->pConductor = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->conductorLen);
2314
2315 #ifdef __MMFILE_TEST_MODE__
2316                                                         debug_msg("pInfo->pConductor returned = (%s), pInfo->conductorLen(%d)\n", pInfo->pConductor, pInfo->conductorLen);
2317 #endif
2318                                                         pInfo->tagV2Info.bConductorMarked = true;
2319                                                 } else if (strncmp((char *)CompTmp, "TALB", 4) == 0 && pInfo->tagV2Info.bAlbumMarked == false) {
2320                                                         pInfo->pAlbum = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->albumLen);
2321
2322 #ifdef __MMFILE_TEST_MODE__
2323                                                         debug_msg("pInfo->pAlbum returned = (%s), pInfo->albumLen(%d)\n", pInfo->pAlbum, pInfo->albumLen);
2324 #endif
2325                                                         pInfo->tagV2Info.bAlbumMarked = true;
2326                                                 } else if (strncmp((char *)CompTmp, "TYER", 4) == 0 && pInfo->tagV2Info.bYearMarked == false) {
2327                                                         pInfo->pYear = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->yearLen);
2328
2329 #ifdef __MMFILE_TEST_MODE__
2330                                                         debug_msg("pInfo->pYear returned = (%s), pInfo->yearLen(%d)\n", pInfo->pYear, pInfo->yearLen);
2331 #endif
2332                                                         pInfo->tagV2Info.bYearMarked = true;
2333                                                 } else if (strncmp((char *)CompTmp, "COMM", 4) == 0 && pInfo->tagV2Info.bDescriptionMarked == false) {
2334                                                         if (realCpyFrameNum > 3) {
2335                                                                 realCpyFrameNum -= 3;
2336                                                                 tmp = 3;
2337
2338                                                                 /*pExtContent[tmp+1] value should't have encoding value */
2339                                                                 if (pExtContent[tmp] == 0x00 || pExtContent[tmp] == 0xFF || pExtContent[tmp] == 0xFE) {
2340                                                                         if ((IS_ENCODEDBY_UTF16(pExtContent + tmp) || IS_ENCODEDBY_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 2) {
2341                                                                                 while ((NEWLINE_OF_UTF16(pExtContent + tmp) || NEWLINE_OF_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 4) {
2342                                                                                         realCpyFrameNum -= 4;
2343                                                                                         tmp += 4;
2344                                                                                 }
2345
2346                                                                                 if (IS_ENCODEDBY_UTF16(pExtContent + tmp) && (realCpyFrameNum > 2)) {
2347                                                                                         realCpyFrameNum -= 2;
2348                                                                                         tmp += 2;
2349                                                                                         textEncodingType = AV_ID3V2_UTF16;
2350                                                                                 } else if (IS_ENCODEDBY_UTF16_R(pExtContent + tmp) && (realCpyFrameNum > 2)) {
2351                                                                                         realCpyFrameNum -= 2;
2352                                                                                         tmp += 2;
2353                                                                                         textEncodingType = AV_ID3V2_UTF16_BE;
2354                                                                                 } else if (IS_ENCODEDBY_UTF16(pExtContent + tmp + 1) && (realCpyFrameNum > 3)) {
2355                                                                                         realCpyFrameNum -= 3;
2356                                                                                         tmp += 3;
2357                                                                                         textEncodingType = AV_ID3V2_UTF16;
2358                                                                                 } else if (IS_ENCODEDBY_UTF16_R(pExtContent + tmp + 1)  && (realCpyFrameNum > 3)) {
2359                                                                                         realCpyFrameNum -= 3;
2360                                                                                         tmp += 3;
2361                                                                                         textEncodingType = AV_ID3V2_UTF16_BE;
2362                                                                                 } else {
2363 #ifdef __MMFILE_TEST_MODE__
2364                                                                                         debug_msg("pInfo->pComment Never Get Here!!\n");
2365 #endif
2366                                                                                 }
2367                                                                         } else {
2368                                                                                 while ((pExtContent[tmp] < 0x20) && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
2369                                                                                         realCpyFrameNum--;
2370                                                                                         tmp++;
2371                                                                                 }
2372                                                                                 textEncodingType = AV_ID3V2_ISO_8859;
2373                                                                         }
2374
2375 #ifdef __MMFILE_TEST_MODE__
2376                                                                         debug_msg("tmp(%d) textEncodingType(%d), realCpyFrameNum(%d)\n", tmp, textEncodingType, realCpyFrameNum);
2377 #endif
2378
2379                                                                         pInfo->pComment = mmfile_string_convert((const char *)&pExtContent[tmp], realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->commentLen);
2380                                                                 } else {
2381 #ifdef __MMFILE_TEST_MODE__
2382                                                                         debug_msg("failed to get Comment Info tmp(%d), purelyFramelen - encodingOffSet(%d)\n", tmp, purelyFramelen - encodingOffSet);
2383 #endif
2384                                                                         pInfo->commentLen = 0;
2385                                                                 }
2386                                                         } else {
2387 #ifdef __MMFILE_TEST_MODE__
2388                                                                 debug_msg("Description info too small to parse realCpyFrameNum(%d)\n", realCpyFrameNum);
2389 #endif
2390                                                                 pInfo->commentLen = 0;
2391                                                         }
2392                                                         tmp = 0;
2393
2394 #ifdef __MMFILE_TEST_MODE__
2395                                                         debug_msg("pInfo->pComment returned = (%s), pInfo->commentLen(%d)\n", pInfo->pComment, pInfo->commentLen);
2396 #endif
2397                                                         pInfo->tagV2Info.bDescriptionMarked = true;
2398                                                 } else if (strncmp((char *)CompTmp, "SYLT", 4) == 0 && pInfo->tagV2Info.bSyncLyricsMarked == false) {
2399                                                         int idx = 0;
2400                                                         int copy_len = 0;
2401                                                         int copy_start_pos = tmp;
2402                                                         AvSynclyricsInfo *synclyrics_info = NULL;
2403                                                         GList *synclyrics_info_list = NULL;
2404
2405                                                         if (realCpyFrameNum > 5) {
2406                                                                 realCpyFrameNum -= 5;
2407                                                                 tmp = 5;
2408
2409                                                                 /*pExtContent[tmp+1] value should't have encoding value */
2410                                                                 if (pExtContent[tmp] == 0x00 || pExtContent[tmp] == 0xFF || pExtContent[tmp] == 0xFE) {
2411                                                                         if ((IS_ENCODEDBY_UTF16(pExtContent + tmp) || IS_ENCODEDBY_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 2) {
2412                                                                                 while ((NEWLINE_OF_UTF16(pExtContent + tmp) || NEWLINE_OF_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 4) {
2413                                                                                         realCpyFrameNum -= 4;
2414                                                                                         tmp += 4;
2415                                                                                 }
2416
2417                                                                                 if (IS_ENCODEDBY_UTF16(pExtContent + tmp) && (realCpyFrameNum > 2)) {
2418                                                                                         realCpyFrameNum -= 2;
2419                                                                                         tmp += 2;
2420                                                                                         textEncodingType = AV_ID3V2_UTF16;
2421                                                                                 } else if (IS_ENCODEDBY_UTF16_R(pExtContent + tmp) && (realCpyFrameNum > 2)) {
2422                                                                                         realCpyFrameNum -= 2;
2423                                                                                         tmp += 2;
2424                                                                                         textEncodingType = AV_ID3V2_UTF16_BE;
2425                                                                                 } else if (IS_ENCODEDBY_UTF16(pExtContent + tmp + 1) && (realCpyFrameNum > 3)) {
2426                                                                                         realCpyFrameNum -= 3;
2427                                                                                         tmp += 3;
2428                                                                                         textEncodingType = AV_ID3V2_UTF16;
2429                                                                                 } else if (IS_ENCODEDBY_UTF16_R(pExtContent + tmp + 1)  && (realCpyFrameNum > 3)) {
2430                                                                                         realCpyFrameNum -= 3;
2431                                                                                         tmp += 3;
2432                                                                                         textEncodingType = AV_ID3V2_UTF16_BE;
2433                                                                                 } else {
2434 #ifdef __MMFILE_TEST_MODE__
2435                                                                                         debug_msg("pInfo->pSyncLyrics Never Get Here!!\n");
2436 #endif
2437                                                                                 }
2438                                                                         } else {
2439                                                                                 while ((pExtContent[tmp] < 0x20) && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
2440                                                                                         realCpyFrameNum--;
2441                                                                                         tmp++;
2442                                                                                 }
2443                                                                                 textEncodingType = AV_ID3V2_ISO_8859;
2444                                                                         }
2445
2446 #ifdef __MMFILE_TEST_MODE__
2447                                                                         debug_msg("tmp(%d) textEncodingType(%d), realCpyFrameNum(%d)\n", tmp, textEncodingType, realCpyFrameNum);
2448 #endif
2449
2450                                                                         if (realCpyFrameNum < MMFILE_SYNC_LYRIC_INFO_MIN_LEN) {
2451 #ifdef __MMFILE_TEST_MODE__
2452                                                                                 debug_msg("failed to get Synchronised lyrics Info realCpyFramNum(%d)\n", realCpyFrameNum);
2453 #endif
2454                                                                                 pInfo->syncLyricsNum = 0;
2455                                                                         } else {
2456                                                                                 if (textEncodingType == AV_ID3V2_UTF16) {
2457                                                                                         debug_warning("[AV_ID3V2_UTF16] not implemented\n");
2458                                                                                 } else if (textEncodingType == AV_ID3V2_UTF16_BE) {
2459                                                                                         debug_warning("[AV_ID3V2_UTF16_BE] not implemented\n");
2460                                                                                 } else {
2461                                                                                         for (idx = 0; idx < realCpyFrameNum; idx++) {
2462                                                                                                 if (pExtContent[tmp + idx] == 0x00) {
2463                                                                                                         synclyrics_info = (AvSynclyricsInfo *)malloc(sizeof(AvSynclyricsInfo));
2464
2465                                                                                                         if (synclyrics_info != NULL) {
2466                                                                                                                 if (textEncodingType == AV_ID3V2_UTF8) {
2467                                                                                                                         synclyrics_info->lyric_info = mmfile_malloc(copy_len + 1);
2468                                                                                                                         if (synclyrics_info->lyric_info != NULL) {
2469                                                                                                                                 memset(synclyrics_info->lyric_info, 0, copy_len + 1);
2470                                                                                                                                 memcpy(synclyrics_info->lyric_info, pExtContent + copy_start_pos, copy_len);
2471                                                                                                                                 synclyrics_info->lyric_info[copy_len + 1] = '\0';
2472                                                                                                                         }
2473                                                                                                                 } else {
2474                                                                                                                         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);
2475                                                                                                                 }
2476
2477                                                                                                                 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];
2478                                                                                                                 idx += 4;
2479                                                                                                                 copy_start_pos = tmp + idx + 1;
2480 #ifdef __MMFILE_TEST_MODE__
2481                                                                                                                 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);
2482 #endif
2483                                                                                                                 copy_len = 0;
2484                                                                                                                 synclyrics_info_list = g_list_append(synclyrics_info_list, synclyrics_info);
2485                                                                                                         }
2486                                                                                                 }
2487                                                                                                 copy_len++;
2488                                                                                         }
2489                                                                                         pInfo->pSyncLyrics = synclyrics_info_list;
2490                                                                                         pInfo->syncLyricsNum = g_list_length(pInfo->pSyncLyrics);
2491                                                                                 }
2492                                                                         }
2493                                                                 } else {
2494 #ifdef __MMFILE_TEST_MODE__
2495                                                                         debug_msg("failed to get Synchronised lyrics Info tmp(%d), purelyFramelen - encodingOffSet(%d)\n", tmp, purelyFramelen - encodingOffSet);
2496 #endif
2497                                                                         pInfo->syncLyricsNum = 0;
2498                                                                 }
2499                                                         } else {
2500 #ifdef __MMFILE_TEST_MODE__
2501                                                                 debug_msg("Synchronised lyrics too small to parse realCpyFrameNum(%d)\n", realCpyFrameNum);
2502 #endif
2503                                                                 pInfo->syncLyricsNum = 0;
2504                                                         }
2505                                                         tmp = 0;
2506
2507 #ifdef __MMFILE_TEST_MODE__
2508                                                         debug_msg("pInfo->pSyncLyrics returned = (%s), pInfo->syncLyricsNum(%d)\n", pInfo->pSyncLyrics, pInfo->syncLyricsNum);
2509 #endif
2510                                                         pInfo->tagV2Info.bSyncLyricsMarked = true;
2511                                                 } else if (strncmp((char *)CompTmp, "USLT", 4) == 0 && pInfo->tagV2Info.bUnsyncLyricsMarked == false) {
2512                                                         char *lang_info = strndup((char *)pExtContent, 3);
2513
2514                                                         if (realCpyFrameNum > 3) {
2515                                                                 realCpyFrameNum -= 3;
2516                                                                 tmp = 3;
2517
2518                                                                 /*find start of lyrics */
2519                                                                 while (1) {
2520                                                                         if (pExtContent[tmp] == 0x00) {
2521                                                                                 if (pExtContent[tmp + 1] == 0x00) {
2522                                                                                         realCpyFrameNum -= 2;
2523                                                                                         tmp += 2;
2524                                                                                 }
2525                                                                                 break;
2526                                                                         } else {
2527                                                                                 realCpyFrameNum--;
2528                                                                                 tmp++;
2529                                                                         }
2530                                                                 }
2531
2532                                                                 /*pExtContent[tmp+1] value should't have encoding value */
2533 #ifdef __MMFILE_TEST_MODE__
2534                                                                 debug_msg("tpExtContent[%d] %x\n", tmp, pExtContent[tmp]);
2535 #endif
2536                                                                 if (pExtContent[tmp] == 0x00 || pExtContent[tmp] == 0xFF || pExtContent[tmp] == 0xFE) {
2537                                                                         if ((IS_ENCODEDBY_UTF16(pExtContent + tmp) || IS_ENCODEDBY_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 2) {
2538                                                                                 while ((NEWLINE_OF_UTF16(pExtContent + tmp) || NEWLINE_OF_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 4) {
2539                                                                                         realCpyFrameNum -= 4;
2540                                                                                         tmp += 4;
2541                                                                                 }
2542
2543                                                                                 if (IS_ENCODEDBY_UTF16(pExtContent + tmp) && (realCpyFrameNum > 2)) {
2544                                                                                         realCpyFrameNum -= 2;
2545                                                                                         tmp += 2;
2546                                                                                         textEncodingType = AV_ID3V2_UTF16;
2547                                                                                 } else if (IS_ENCODEDBY_UTF16_R(pExtContent + tmp) && (realCpyFrameNum > 2)) {
2548                                                                                         realCpyFrameNum -= 2;
2549                                                                                         tmp += 2;
2550                                                                                         textEncodingType = AV_ID3V2_UTF16_BE;
2551                                                                                 } else if (IS_ENCODEDBY_UTF16(pExtContent + tmp + 1) && (realCpyFrameNum > 3)) {
2552                                                                                         realCpyFrameNum -= 3;
2553                                                                                         tmp += 3;
2554                                                                                         textEncodingType = AV_ID3V2_UTF16;
2555                                                                                 } else if (IS_ENCODEDBY_UTF16_R(pExtContent + tmp + 1)  && (realCpyFrameNum > 3)) {
2556                                                                                         realCpyFrameNum -= 3;
2557                                                                                         tmp += 3;
2558                                                                                         textEncodingType = AV_ID3V2_UTF16_BE;
2559                                                                                 } else {
2560 #ifdef __MMFILE_TEST_MODE__
2561                                                                                         debug_msg("pInfo->pUnsyncLyrics Never Get Here!!\n");
2562 #endif
2563                                                                                 }
2564                                                                         } else {
2565                                                                                 while ((pExtContent[tmp] < 0x20) && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
2566                                                                                         realCpyFrameNum--;
2567                                                                                         tmp++;
2568                                                                                 }
2569                                                                                 textEncodingType = AV_ID3V2_ISO_8859;
2570                                                                         }
2571
2572 #ifdef __MMFILE_TEST_MODE__
2573                                                                         debug_msg("tmp(%d) textEncodingType(%d), realCpyFrameNum(%d)\n", tmp, textEncodingType, realCpyFrameNum);
2574 #endif
2575
2576                                                                         char *char_set = NULL;
2577                                                                         if (textEncodingType == AV_ID3V2_ISO_8859) {
2578                                                                                 if (lang_info != NULL && !strcasecmp(lang_info, "KOR")) {
2579                                                                                         char_set = strdup("EUC-KR");
2580                                                                                 } else {
2581                                                                                         char_set = mmfile_get_charset((const char *)&pExtContent[tmp]);
2582                                                                                 }
2583                                                                                 _FREE_EX(lang_info);
2584                                                                         }
2585
2586                                                                         if (char_set == NULL) {
2587                                                                                 pInfo->pUnsyncLyrics = mmfile_string_convert((const char *)&pExtContent[tmp], realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->unsynclyricsLen);
2588                                                                         } else {
2589                                                                                 pInfo->pUnsyncLyrics = mmfile_string_convert((const char *)&pExtContent[tmp], realCpyFrameNum, "UTF-8", char_set, NULL, (unsigned int *)&pInfo->unsynclyricsLen);
2590                                                                                 _FREE_EX(char_set);
2591                                                                         }
2592                                                                 } else {
2593 #ifdef __MMFILE_TEST_MODE__
2594                                                                         debug_msg("failed to get Unsynchronised lyrics Info tmp(%d), purelyFramelen - encodingOffSet(%d)\n", tmp, purelyFramelen - encodingOffSet);
2595 #endif
2596                                                                         pInfo->unsynclyricsLen = 0;
2597                                                                 }
2598                                                         } else {
2599 #ifdef __MMFILE_TEST_MODE__
2600                                                                 debug_msg("Unsynchronised lyrics too small to parse realCpyFrameNum(%d)\n", realCpyFrameNum);
2601 #endif
2602                                                                 pInfo->unsynclyricsLen = 0;
2603                                                         }
2604                                                         tmp = 0;
2605
2606 #ifdef __MMFILE_TEST_MODE__
2607                                                         debug_msg("pInfo->pUnsyncLyrics returned = (%s), pInfo->unsynclyricsLen(%d)\n", pInfo->pUnsyncLyrics, pInfo->unsynclyricsLen);
2608 #endif
2609                                                         pInfo->tagV2Info.bUnsyncLyricsMarked = true;
2610                                                         mmfile_free(lang_info);
2611                                                 } else if (strncmp((char *)CompTmp, "TCON", 4) == 0 && pInfo->tagV2Info.bGenreMarked == false) {
2612                                                         pInfo->pGenre = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->genreLen);
2613
2614 #ifdef __MMFILE_TEST_MODE__
2615                                                         debug_msg("pInfo->pGenre returned = (%s), pInfo->genreLen(%d)\n", pInfo->pGenre, pInfo->genreLen);
2616 #endif
2617
2618                                                         if ((pInfo->pGenre != NULL) && (pInfo->genreLen > 0)) {
2619                                                                 bool ret = FALSE;
2620                                                                 int int_genre = -1;
2621
2622                                                                 ret = is_numeric(pInfo->pGenre, pInfo->genreLen);
2623
2624                                                                 if (ret == TRUE) {
2625                                                                         sscanf(pInfo->pGenre, "%d", &int_genre);
2626 #ifdef __MMFILE_TEST_MODE__
2627                                                                         debug_msg("genre information is inteager [%d]\n", int_genre);
2628 #endif
2629
2630                                                                         /*Change int to string */
2631                                                                         if ((0 <= int_genre) && (int_genre < GENRE_COUNT - 1)) {
2632                                                                                 /*save genreinfo like "(123)". mm_file_id3tag_restore_content_info convert it to string*/
2633                                                                                 char tmp_genre[6] = {0, };      /*ex. "(123)+NULL"*/
2634                                                                                 int tmp_genre_len = 0;
2635
2636                                                                                 memset(tmp_genre, 0, 6);
2637                                                                                 snprintf(tmp_genre, sizeof(tmp_genre), "(%d)", int_genre);
2638
2639                                                                                 tmp_genre_len = strlen(tmp_genre);
2640                                                                                 if (tmp_genre_len > 0) {
2641                                                                                         if (pInfo->pGenre) _FREE_EX(pInfo->pGenre);
2642                                                                                         pInfo->pGenre = mmfile_malloc(sizeof(char) * (tmp_genre_len + 1));
2643                                                                                         if (pInfo->pGenre) {
2644                                                                                                 strncpy(pInfo->pGenre, tmp_genre, tmp_genre_len);
2645                                                                                                 pInfo->pGenre[tmp_genre_len] = 0;
2646                                                                                         }
2647                                                                                 }
2648                                                                         }
2649                                                                 }
2650                                                         }
2651
2652                                                         pInfo->tagV2Info.bGenreMarked = true;
2653                                                 } else if (strncmp((char *)CompTmp, "TRCK", 4) == 0 && pInfo->tagV2Info.bTrackNumMarked == false) {
2654                                                         pInfo->pTrackNum = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->tracknumLen);
2655
2656 #ifdef __MMFILE_TEST_MODE__
2657                                                         debug_msg("pInfo->pTrackNum returned = (%s), pInfo->tracknumLen(%d)\n", pInfo->pTrackNum, pInfo->tracknumLen);
2658 #endif
2659                                                         pInfo->tagV2Info.bTrackNumMarked = true;
2660                                                 } else if (strncmp((char *)CompTmp, "TENC", 4) == 0 && pInfo->tagV2Info.bEncByMarked == false) {
2661                                                         pInfo->pEncBy = mmfile_string_convert((char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->encbyLen);
2662
2663 #ifdef __MMFILE_TEST_MODE__
2664                                                         debug_msg("pInfo->pEncBy returned = (%s), pInfo->encbyLen(%d)\n", pInfo->pEncBy, pInfo->encbyLen);
2665 #endif
2666                                                         pInfo->tagV2Info.bEncByMarked = true;
2667                                                 } else if (strncmp((char *)CompTmp, "WXXX", 4) == 0 && pInfo->tagV2Info.bURLMarked == false) {
2668                                                         pInfo->pURL = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->urlLen);
2669
2670 #ifdef __MMFILE_TEST_MODE__
2671                                                         debug_msg("pInfo->pURL returned = (%s), pInfo->urlLen(%d)\n", pInfo->pURL, pInfo->urlLen);
2672 #endif
2673                                                         pInfo->tagV2Info.bURLMarked = true;
2674                                                 } else if (strncmp((char *)CompTmp, "TCOP", 4) == 0 && pInfo->tagV2Info.bCopyRightMarked == false) {
2675                                                         pInfo->pCopyright = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->copyrightLen);
2676
2677 #ifdef __MMFILE_TEST_MODE__
2678                                                         debug_msg("pInfo->pCopyright returned = (%s), pInfo->copyrightLen(%d)\n", pInfo->pCopyright, pInfo->copyrightLen);
2679 #endif
2680                                                         pInfo->tagV2Info.bCopyRightMarked = true;
2681                                                 } else if (strncmp((char *)CompTmp, "TOPE", 4) == 0 && pInfo->tagV2Info.bOriginArtistMarked == false) {
2682                                                         pInfo->pOriginArtist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->originartistLen);
2683
2684 #ifdef __MMFILE_TEST_MODE__
2685                                                         debug_msg("pInfo->pOriginArtist returned = (%s), pInfo->originartistLen(%d)\n", pInfo->pOriginArtist, pInfo->originartistLen);
2686 #endif
2687                                                         pInfo->tagV2Info.bOriginArtistMarked = true;
2688                                                 } else if (strncmp((char *)CompTmp, "TCOM", 4) == 0 && pInfo->tagV2Info.bComposerMarked == false) {
2689                                                         pInfo->pComposer = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->composerLen);
2690
2691 #ifdef __MMFILE_TEST_MODE__
2692                                                         debug_msg("pInfo->pComposer returned = (%s), pInfo->composerLen(%d)\n", pInfo->pComposer, pInfo->composerLen);
2693 #endif
2694                                                         pInfo->tagV2Info.bComposerMarked = true;
2695                                                 } else if (strncmp((char *)CompTmp, "TRDA", 4) == 0 && pInfo->tagV2Info.bRecDateMarked == false) {
2696                                                         pInfo->pRecDate = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->recdateLen);
2697
2698 #ifdef __MMFILE_TEST_MODE__
2699                                                         debug_msg("pInfo->pRecDate returned = (%s), pInfo->recdateLen(%d)\n", pInfo->pRecDate, pInfo->recdateLen);
2700 #endif
2701                                                         pInfo->tagV2Info.bRecDateMarked = true;
2702                                                 } else if (strncmp((char *)CompTmp, "APIC", 4) == 0 && pInfo->tagV2Info.bImageMarked == false && realCpyFrameNum <= 2000000) {
2703                                                         debug_msg("text encoding %d \n", textEncodingType);
2704
2705                                                         if (pExtContent[0] != '\0') {
2706                                                                 for (inx = 0; inx < MP3_ID3_IMAGE_MIME_TYPE_MAX_LENGTH - 1; inx++)
2707                                                                         pInfo->imageInfo.imageMIMEType[inx] = '\0';/*ini mimetype variable */
2708
2709                                                                 while ((checkImgMimeTypeMax < MP3_ID3_IMAGE_MIME_TYPE_MAX_LENGTH - 1) && pExtContent[checkImgMimeTypeMax] != '\0') {
2710                                                                         pInfo->imageInfo.imageMIMEType[checkImgMimeTypeMax] = pExtContent[checkImgMimeTypeMax];
2711                                                                         checkImgMimeTypeMax++;
2712                                                                 }
2713                                                                 pInfo->imageInfo.imgMimetypeLen = checkImgMimeTypeMax;
2714                                                         } else {
2715                                                                 pInfo->imageInfo.imgMimetypeLen = 0;
2716 #ifdef __MMFILE_TEST_MODE__
2717                                                                 debug_msg("APIC image's not included to MIME type\n");
2718 #endif
2719                                                         }
2720
2721                                                         imgstartOffset += checkImgMimeTypeMax;
2722
2723                                                         if (strncmp(pInfo->imageInfo.imageMIMEType, MIME_PRFIX, strlen(MIME_PRFIX)) != 0) {
2724                                                                 pInfo->imageInfo.imgMimetypeLen = 0;
2725                                                                 debug_error("APIC NOT VALID");
2726                                                                 continue;
2727                                                         }
2728
2729                                                         if ((pExtContent[imgstartOffset] == '\0') && (realCpyFrameNum - imgstartOffset > 0)) {
2730                                                                 imgstartOffset++;/*endofMIME(1byte) */
2731 #ifdef __MMFILE_TEST_MODE__
2732                                                                 debug_msg("after scaning Mime type imgstartOffset(%d) value!\n", imgstartOffset);
2733 #endif
2734
2735                                                                 if (pExtContent[imgstartOffset] < AV_ID3V2_PICTURE_TYPE_MAX) {
2736                                                                         pInfo->imageInfo.pictureType = pExtContent[imgstartOffset];
2737                                                                 } else {
2738 #ifdef __MMFILE_TEST_MODE__
2739                                                                         debug_msg("APIC image has invalid picture type(0x%x)\n", pExtContent[imgstartOffset]);
2740 #endif
2741                                                                 }
2742                                                                 imgstartOffset++;/*PictureType(1byte) */
2743 #ifdef __MMFILE_TEST_MODE__
2744                                                                 debug_msg("after scaning PictureType imgstartOffset(%d) value!\n", imgstartOffset);
2745 #endif
2746
2747                                                                 if (pExtContent[imgstartOffset] != 0x0) {
2748                                                                         int cur_pos = 0;
2749                                                                         int dis_len = 0;
2750                                                                         int new_dis_len = 0;
2751                                                                         char *tmp_desc = NULL;
2752
2753                                                                         while (1) {
2754                                                                                 if (pExtContent[imgstartOffset + cur_pos] == '\0') {
2755                                                                                         if (realCpyFrameNum < imgstartOffset + cur_pos) {
2756                                                                                                 debug_error("End of APIC Tag %d %d %d\n", realCpyFrameNum, imgstartOffset, cur_pos);
2757                                                                                                 break;
2758                                                                                         }
2759                                                                                         /*check end of image description*/
2760                                                                                         if ((pExtContent[imgstartOffset + cur_pos + 1] == gTagJPEGHeader[0]) ||
2761                                                                                             (pExtContent[imgstartOffset + cur_pos + 1] == gTagPNGHeader[0])) {
2762 #ifdef __MMFILE_TEST_MODE__
2763                                                                                                 debug_msg("length of description (%d)", cur_pos);
2764 #endif
2765
2766                                                                                                 break;
2767                                                                                         }
2768                                                                                 }
2769                                                                                 cur_pos++;
2770                                                                         }
2771
2772                                                                         dis_len = cur_pos + 1;
2773
2774                                                                         tmp_desc = mmfile_malloc(sizeof(char) * dis_len);
2775                                                                         memcpy(tmp_desc, pExtContent + imgstartOffset, dis_len);
2776
2777                                                                         /*convert description*/
2778                                                                         pInfo->imageInfo.imageDescription = mmfile_string_convert(tmp_desc, dis_len, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&new_dis_len);
2779 #ifdef __MMFILE_TEST_MODE__
2780                                                                         debug_msg("new_desc %s(%d)\n", pInfo->imageInfo.imageDescription, new_dis_len);
2781 #endif
2782                                                                         mmfile_free(tmp_desc);
2783
2784                                                                         pInfo->imageInfo.imgDesLen = new_dis_len; /**/
2785                                                                         imgstartOffset += cur_pos;
2786                                                                 } else {
2787                                                                         pInfo->imageInfo.imgDesLen = 0;
2788 #ifdef __MMFILE_TEST_MODE__
2789                                                                         debug_msg("APIC image's not included to Description!!!\n");
2790 #endif
2791                                                                 }
2792
2793                                                                 if ((pExtContent[imgstartOffset] == '\0') && (realCpyFrameNum - imgstartOffset > 0)) {
2794                                                                         imgstartOffset++; /* endofDesceriptionType(1byte) */
2795
2796                                                                         while (pExtContent[imgstartOffset] == '\0') {   /*some content has useless '\0' in front of picture data */
2797                                                                                 imgstartOffset++;
2798                                                                         }
2799
2800 #ifdef __MMFILE_TEST_MODE__
2801                                                                         debug_msg("after scaning imgDescription imgstartOffset(%d) value!\n", imgstartOffset);
2802 #endif
2803
2804                                                                         if (realCpyFrameNum - imgstartOffset > 0) {
2805                                                                                 pInfo->imageInfo.imageLen = realCpyFrameNum - imgstartOffset;
2806                                                                                 pInfo->imageInfo.pImageBuf = mmfile_malloc(pInfo->imageInfo.imageLen + 1);
2807
2808                                                                                 if (pInfo->imageInfo.pImageBuf != NULL) {
2809                                                                                         memcpy(pInfo->imageInfo.pImageBuf, pExtContent + imgstartOffset, pInfo->imageInfo.imageLen);
2810                                                                                         pInfo->imageInfo.pImageBuf[pInfo->imageInfo.imageLen] = 0;
2811                                                                                 }
2812
2813                                                                                 if (IS_INCLUDE_URL(pInfo->imageInfo.imageMIMEType))
2814                                                                                         pInfo->imageInfo.bURLInfo = true; /*if mimetype is "-->", image date has an URL */
2815                                                                         } else {
2816 #ifdef __MMFILE_TEST_MODE__
2817                                                                                 debug_msg("No APIC image!! realCpyFrameNum(%d) - imgstartOffset(%d)\n", realCpyFrameNum, imgstartOffset);
2818 #endif
2819                                                                         }
2820 #ifdef __MMFILE_TEST_MODE__
2821                                                                         debug_msg("pInfo->imageInfo.imageLen(%d), imgstartOffset(%d)!\n", pInfo->imageInfo.imageLen, imgstartOffset);
2822 #endif
2823                                                                 } else {
2824 #ifdef __MMFILE_TEST_MODE__
2825                                                                         debug_msg("pExtContent[imgstartOffset](%d) value should setted NULL value for end of description! realCpyFrameNum - imgstartOffset(%d)\n",
2826                                                                                         pExtContent[imgstartOffset], realCpyFrameNum - imgstartOffset);
2827 #endif
2828                                                                 }
2829                                                         } else {
2830 #ifdef __MMFILE_TEST_MODE__
2831                                                                 debug_msg("pExtContent[imgstartOffset](%d) value should setted NULL value for end of mimetype! realCpyFrameNum - imgstartOffset(%d)\n",
2832                                                                                         pExtContent[imgstartOffset], realCpyFrameNum - imgstartOffset);
2833 #endif
2834                                                         }
2835
2836                                                         checkImgMimeTypeMax = 0;
2837                                                         inx = 0;
2838                                                         imgstartOffset = 0;
2839                                                         pInfo->tagV2Info.bImageMarked = true;
2840
2841                                                 } else {
2842 #ifdef __MMFILE_TEST_MODE__
2843                                                         debug_msg("CompTmp(%s) This Frame ID currently not Supports!!\n", CompTmp);
2844 #endif
2845                                                 }
2846                                         }
2847
2848                                 } else {
2849 #ifdef __MMFILE_TEST_MODE__
2850                                         debug_msg("All of the pExtContent Values are NULL\n");
2851 #endif
2852                                 }
2853                         } else {
2854                                 curPos += purelyFramelen;
2855                                 if (purelyFramelen != 0)
2856                                         needToloopv2taglen = MP3_TAGv2_23_TXT_HEADER_LEN;
2857 #ifdef __MMFILE_TEST_MODE__
2858                                 debug_msg("This Frame's size is Zero! purelyFramelen(%d)\n", purelyFramelen);
2859 #endif
2860                         }
2861
2862                         if (pExtContent)        _FREE_EX(pExtContent);
2863                         memset(CompTmp, 0, 4);
2864
2865                         if (curPos < taglen) {
2866                                 needToloopv2taglen -= oneFrameLen;
2867                                 v2numOfFrames++;
2868                         } else
2869                                 needToloopv2taglen = MP3_TAGv2_23_TXT_HEADER_LEN;
2870                         oneFrameLen = 0;
2871                         encodingOffSet = 0;
2872                         realCpyFrameNum = 0;
2873                         textEncodingType = 0;
2874                         purelyFramelen = 0;
2875
2876                 }
2877         }
2878
2879         release_characterset_array(charset_array);
2880
2881         if (taglen)
2882                 return true;
2883         else
2884                 return false;
2885
2886 }
2887
2888 EXPORT_API
2889 bool mm_file_id3tag_parse_v224(AvFileContentInfo *pInfo, unsigned char *buffer)
2890 {
2891         unsigned long taglen = 0;
2892         unsigned long needToloopv2taglen;
2893         unsigned long oneFrameLen = 0;
2894         unsigned long v2numOfFrames = 0;
2895         unsigned long curPos = 0;
2896         char CompTmp[5];
2897         unsigned char *pExtContent = NULL;
2898         unsigned long purelyFramelen = 0;
2899         unsigned int encodingOffSet = 0;
2900         int inx = 0, realCpyFrameNum = 0, checkImgMimeTypeMax = 0, imgstartOffset = 0,  tmp = 0;
2901         int textEncodingType = 0;
2902         char **charset_array = NULL;
2903         const char *MIME_PRFIX = "image/";
2904
2905         make_characterset_array(&charset_array);
2906
2907         init_content_info(pInfo);
2908
2909         taglen = pInfo->tagV2Info.tagLen;
2910         needToloopv2taglen = taglen - MP3_TAGv2_HEADER_LEN;
2911         curPos = MP3_TAGv2_HEADER_LEN;
2912
2913 #ifdef __MMFILE_TEST_MODE__
2914         debug_msg("ID3tag v224--------------------------------------------------------------\n");
2915 #endif
2916
2917         /* check Extended Header */
2918         if (buffer[5] & 0x40) {
2919                 /* if extended header exists, skip it*/
2920                 int extendedHeaderLen = (unsigned long)buffer[10] << 21 | (unsigned long)buffer[11] << 14 | (unsigned long)buffer[12] << 7  | (unsigned long)buffer[13];
2921
2922 #ifdef __MMFILE_TEST_MODE__
2923                 debug_msg("--------------- extendedHeaderLen = %d\n", extendedHeaderLen);
2924 #endif
2925
2926                 if (extendedHeaderLen > (int)(taglen - curPos)) {
2927                         debug_error("extended header too long.\n");
2928                 } else {
2929                         curPos += extendedHeaderLen;
2930                 }
2931         }
2932
2933         if (needToloopv2taglen - MP3_TAGv2_23_TXT_HEADER_LEN > MP3_TAGv2_23_TXT_HEADER_LEN) {
2934                 v2numOfFrames = 1;
2935                 while (needToloopv2taglen > MP3_TAGv2_23_TXT_HEADER_LEN) {
2936                         if ((buffer[curPos] < '0' || buffer[curPos] > 'Z') || (buffer[curPos + 1] < '0' || buffer[curPos + 1] > 'Z')
2937                             || (buffer[curPos + 2] < '0' || buffer[curPos + 2] > 'Z') || (buffer[curPos + 3] < '0' || buffer[curPos + 3] > 'Z'))
2938                                 break;
2939
2940                         memcpy(CompTmp, &buffer[curPos], 4);
2941
2942                         CompTmp[4] = 0;
2943                         oneFrameLen = MP3_TAGv2_23_TXT_HEADER_LEN;
2944                         oneFrameLen += (unsigned long)buffer[4 + curPos] << 21 | (unsigned long)buffer[5 + curPos] << 14
2945                                                 | (unsigned long)buffer[6 + curPos] << 7 | (unsigned long)buffer[7 + curPos];
2946                         if (oneFrameLen > taglen - curPos)
2947                                 break;
2948
2949                         purelyFramelen = oneFrameLen - MP3_TAGv2_23_TXT_HEADER_LEN;
2950                         curPos += MP3_TAGv2_23_TXT_HEADER_LEN;
2951
2952 #ifdef __MMFILE_TEST_MODE__
2953                         debug_msg("-----------------------------------------------------------------------------------\n");
2954 #endif
2955
2956                         if (oneFrameLen > MP3_TAGv2_23_TXT_HEADER_LEN && purelyFramelen <= taglen - curPos) {
2957                                 curPos += purelyFramelen;
2958
2959                                 /*in case of UTF 16 encoding */
2960                                 /*buffer+(curPos-purelyFramelen) data should '0x01' but in order to expansion, we don't accurately check the value. */
2961                                 if (IS_ENCODEDBY_UTF16(buffer + (curPos - purelyFramelen))) {
2962                                         encodingOffSet = 2;
2963                                         textEncodingType = AV_ID3V2_UTF16;
2964                                 } else if (IS_ENCODEDBY_UTF16_R(buffer + (curPos - purelyFramelen))) {
2965                                         encodingOffSet = 2;
2966                                         textEncodingType = AV_ID3V2_UTF16_BE;
2967                                 } else if (IS_ENCODEDBY_UTF16(buffer + (curPos - purelyFramelen + 1))) {
2968                                         encodingOffSet = 3;
2969                                         textEncodingType = AV_ID3V2_UTF16;
2970                                 } else if (IS_ENCODEDBY_UTF16_R(buffer + (curPos - purelyFramelen + 1))) {
2971                                         encodingOffSet = 3;
2972                                         textEncodingType = AV_ID3V2_UTF16_BE;
2973                                 } else {
2974                                         /*in case of UTF-16 BE encoding */
2975                                         if (buffer[curPos - purelyFramelen] == 0x02) {
2976                                                 encodingOffSet = 1;
2977                                                 while ((buffer[curPos - purelyFramelen + encodingOffSet] == '\0') && (encodingOffSet < purelyFramelen))
2978                                                         encodingOffSet++;/*null skip! */
2979                                                 textEncodingType = AV_ID3V2_UTF16_BE;
2980                                         }
2981                                         /*in case of UTF8 encoding */
2982                                         else if (buffer[curPos - purelyFramelen] == 0x03) {
2983                                                 encodingOffSet = 1;
2984                                                 while ((buffer[curPos - purelyFramelen + encodingOffSet] == '\0') && (encodingOffSet < purelyFramelen))
2985                                                         encodingOffSet++;/*null skip! */
2986                                                 textEncodingType = AV_ID3V2_UTF8;
2987                                         }
2988                                         /*in case of ISO-8859-1 encoding */
2989                                         else {
2990                                                 /*buffer+(curPos-purelyFramelen) data should 0x00 but in order to expansion, we don't accurately check the value. */
2991                                                 encodingOffSet = 1;
2992                                                 while ((buffer[curPos - purelyFramelen + encodingOffSet] < 0x20) && (encodingOffSet < purelyFramelen))
2993                                                         encodingOffSet++;/*less than 0x20 value skip! */
2994                                                 textEncodingType = AV_ID3V2_ISO_8859;
2995                                         }
2996                                 }
2997
2998                                 if (encodingOffSet < purelyFramelen) {
2999                                         realCpyFrameNum = purelyFramelen - encodingOffSet;
3000                                         pExtContent = mmfile_malloc(realCpyFrameNum + 3);
3001
3002                                         if (pExtContent == NULL) {
3003                                                 debug_error("out of memoryu for id3tag parse\n");
3004                                                 continue;
3005                                         }
3006
3007                                         memset(pExtContent, '\0', realCpyFrameNum + 3);
3008
3009                                         if (textEncodingType != AV_ID3V2_UTF16 && textEncodingType != AV_ID3V2_UTF16_BE) {
3010                                                 if (CompTmp[0] == 'T' || (strcmp(CompTmp, "APIC") == 0)) {
3011 #ifdef __MMFILE_TEST_MODE__
3012                                                         debug_msg("get the new text ecoding type\n");
3013 #endif
3014                                                         textEncodingType = buffer[curPos - purelyFramelen + encodingOffSet - 1];
3015                                                 }
3016                                         }
3017
3018                                         if (textEncodingType > AV_ID3V2_MAX) {
3019                                                 debug_msg("WRONG ENCOIDNG TYPE [%d], FRAME[%s]\n", textEncodingType, (char *)CompTmp);
3020                                                 continue;
3021                                         }
3022
3023                                         memcpy(pExtContent, &buffer[curPos - purelyFramelen + encodingOffSet], purelyFramelen - encodingOffSet);
3024
3025                                         if (realCpyFrameNum > 0) {
3026                                                 if (strncmp((char *)CompTmp, "TIT2", 4) == 0 && pInfo->tagV2Info.bTitleMarked == false) {
3027                                                         if (textEncodingType == AV_ID3V2_UTF8) {
3028                                                                 pInfo->pTitle = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3029                                                                 if (pInfo->pTitle) {
3030                                                                         memcpy(pInfo->pTitle, pExtContent, realCpyFrameNum);
3031                                                                         pInfo->pTitle[realCpyFrameNum] = '\0';
3032                                                                         /*string copy with '\0'*/
3033                                                                         pInfo->titleLen = realCpyFrameNum;
3034                                                                         _STRNCPY_EX(pInfo->pTitle, pExtContent, pInfo->titleLen);
3035                                                                 }
3036                                                         } else {
3037                                                                 pInfo->pTitle = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->titleLen);
3038                                                         }
3039
3040 #ifdef __MMFILE_TEST_MODE__
3041                                                         debug_msg("pInfo->pTitle returned = (%s), pInfo->titleLen(%d)\n", pInfo->pTitle, pInfo->titleLen);
3042 #endif
3043                                                         pInfo->tagV2Info.bTitleMarked = true;
3044
3045                                                 } else if (strncmp((char *)CompTmp, "TPE1", 4) == 0 && pInfo->tagV2Info.bArtistMarked == false) {
3046                                                         if (textEncodingType == AV_ID3V2_UTF8) {
3047                                                                 pInfo->pArtist = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3048                                                                 if (pInfo->pArtist) {
3049                                                                         memcpy(pInfo->pArtist, pExtContent, realCpyFrameNum);
3050                                                                         pInfo->pArtist[realCpyFrameNum] = '\0';
3051                                                                         /*string copy with '\0'*/
3052                                                                         pInfo->artistLen = realCpyFrameNum;
3053                                                                         _STRNCPY_EX(pInfo->pArtist, pExtContent, pInfo->artistLen);
3054                                                                 }
3055                                                         } else {
3056                                                                 pInfo->pArtist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->artistLen);
3057                                                         }
3058
3059 #ifdef __MMFILE_TEST_MODE__
3060                                                         debug_msg("pInfo->pArtist returned = (%s), pInfo->artistLen(%d)\n", pInfo->pArtist, pInfo->artistLen);
3061 #endif
3062                                                         pInfo->tagV2Info.bArtistMarked = true;
3063                                                 } else if (strncmp((char *)CompTmp, "TPE2", 4) == 0 && pInfo->tagV2Info.bAlbum_ArtistMarked == false) {
3064                                                         if (textEncodingType == AV_ID3V2_UTF8) {
3065                                                                 pInfo->pAlbum_Artist = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3066                                                                 if (pInfo->pAlbum_Artist) {
3067                                                                         memcpy(pInfo->pAlbum_Artist, pExtContent, realCpyFrameNum);
3068                                                                         pInfo->pAlbum_Artist[realCpyFrameNum] = '\0';
3069                                                                         /*string copy with '\0'*/
3070                                                                         pInfo->album_artistLen = realCpyFrameNum;
3071                                                                         _STRNCPY_EX(pInfo->pAlbum_Artist, pExtContent, pInfo->album_artistLen);
3072                                                                 }
3073                                                         } else {
3074                                                                 pInfo->pAlbum_Artist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->album_artistLen);
3075                                                         }
3076
3077 #ifdef __MMFILE_TEST_MODE__
3078                                                         debug_msg("pInfo->pAlbum_Artist returned = (%s), pInfo->album_artistLen(%d)\n", pInfo->pAlbum_Artist, pInfo->album_artistLen);
3079 #endif
3080                                                         pInfo->tagV2Info.bAlbum_ArtistMarked = true;
3081                                                 } else if (strncmp((char *)CompTmp, "TPE3", 4) == 0 && pInfo->tagV2Info.bConductorMarked == false) {
3082                                                         if (textEncodingType == AV_ID3V2_UTF8) {
3083                                                                 pInfo->pConductor = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3084                                                                 if (pInfo->pConductor) {
3085                                                                         memcpy(pInfo->pConductor, pExtContent, realCpyFrameNum);
3086                                                                         pInfo->pConductor[realCpyFrameNum] = '\0';
3087                                                                         /*string copy with '\0'*/
3088                                                                         pInfo->conductorLen = realCpyFrameNum;
3089                                                                         _STRNCPY_EX(pInfo->pConductor, pExtContent, pInfo->conductorLen);
3090                                                                 }
3091                                                         } else {
3092                                                                 pInfo->pConductor = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->conductorLen);
3093                                                         }
3094
3095 #ifdef __MMFILE_TEST_MODE__
3096                                                         debug_msg("pInfo->pConductor returned = (%s), pInfo->conductorLen(%d)\n", pInfo->pConductor, pInfo->conductorLen);
3097 #endif
3098                                                         pInfo->tagV2Info.bConductorMarked = true;
3099                                                 } else if (strncmp((char *)CompTmp, "TALB", 4) == 0 && pInfo->tagV2Info.bAlbumMarked == false) {
3100                                                         if (textEncodingType == AV_ID3V2_UTF8) {
3101                                                                 pInfo->pAlbum = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3102                                                                 if (pInfo->pAlbum) {
3103                                                                         memcpy(pInfo->pAlbum, pExtContent, realCpyFrameNum);
3104                                                                         pInfo->pAlbum[realCpyFrameNum] = '\0';
3105                                                                         /*string copy with '\0'*/
3106                                                                         pInfo->albumLen = realCpyFrameNum;
3107                                                                         _STRNCPY_EX(pInfo->pAlbum, pExtContent, pInfo->albumLen);
3108                                                                 }
3109                                                         } else {
3110                                                                 pInfo->pAlbum = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->albumLen);
3111                                                         }
3112
3113 #ifdef __MMFILE_TEST_MODE__
3114                                                         debug_msg("pInfo->pAlbum returned = (%s), pInfo->albumLen(%d)\n", pInfo->pAlbum, pInfo->albumLen);
3115 #endif
3116                                                         pInfo->tagV2Info.bAlbumMarked = true;
3117                                                 } 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 */
3118                                                         if (textEncodingType == AV_ID3V2_UTF8) {
3119                                                                 pInfo->pYear = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3120                                                                 if (pInfo->pYear) {
3121                                                                         memcpy(pInfo->pYear, pExtContent, realCpyFrameNum);
3122                                                                         pInfo->pYear[realCpyFrameNum] = '\0';
3123                                                                         /*string copy with '\0'*/
3124                                                                         pInfo->yearLen = realCpyFrameNum;
3125                                                                         _STRNCPY_EX(pInfo->pYear, pExtContent, pInfo->yearLen);
3126                                                                 }
3127                                                         } else {
3128                                                                 pInfo->pYear = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->yearLen);
3129                                                         }
3130
3131 #ifdef __MMFILE_TEST_MODE__
3132                                                         debug_msg("pInfo->pYear returned = (%s), pInfo->yearLen(%d)\n", pInfo->pYear, pInfo->yearLen);
3133 #endif
3134                                                         pInfo->tagV2Info.bYearMarked = true;
3135                                                 } else if (strncmp((char *)CompTmp, "COMM", 4) == 0 && pInfo->tagV2Info.bDescriptionMarked == false) {
3136                                                         if (realCpyFrameNum > 3) {
3137                                                                 realCpyFrameNum -= 3;
3138                                                                 tmp = 3;
3139
3140                                                                 if (textEncodingType == AV_ID3V2_UTF16 || textEncodingType == AV_ID3V2_UTF16_BE) {
3141                                                                         while ((NEWLINE_OF_UTF16(pExtContent + tmp) || NEWLINE_OF_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 4) {
3142                                                                                 realCpyFrameNum -= 4;
3143                                                                                 tmp += 4;
3144                                                                         }
3145
3146                                                                         if ((IS_ENCODEDBY_UTF16(pExtContent + tmp) || IS_ENCODEDBY_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 2) {
3147                                                                                 realCpyFrameNum -= 2;
3148                                                                                 tmp += 2;
3149                                                                                 textEncodingType = AV_ID3V2_UTF16;
3150                                                                         } else {
3151 #ifdef __MMFILE_TEST_MODE__
3152                                                                                 debug_msg("pInfo->pComment Never Get Here!!\n");
3153 #endif
3154                                                                         }
3155                                                                 } else if (textEncodingType == AV_ID3V2_UTF8) {
3156                                                                         while (pExtContent[tmp] < 0x20 && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
3157                                                                                 realCpyFrameNum--;
3158                                                                                 tmp++;
3159                                                                         }
3160                                                                         textEncodingType = AV_ID3V2_UTF8;
3161                                                                 } else {
3162                                                                         while (pExtContent[tmp] < 0x20 && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
3163                                                                                 realCpyFrameNum--;
3164                                                                                 tmp++;
3165                                                                         }
3166                                                                         textEncodingType = AV_ID3V2_ISO_8859;
3167                                                                 }
3168
3169 #ifdef __MMFILE_TEST_MODE__
3170                                                                 debug_msg("tmp(%d) textEncodingType(%d), realCpyFrameNum(%d)\n", tmp, textEncodingType, realCpyFrameNum);
3171 #endif
3172
3173                                                                 if (textEncodingType == AV_ID3V2_UTF8) {
3174                                                                         pInfo->pComment = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3175                                                                         if (pInfo->pComment) {
3176                                                                                 memset(pInfo->pComment, 0, (realCpyFrameNum + 2));
3177                                                                                 memcpy(pInfo->pComment, pExtContent + tmp, realCpyFrameNum);
3178                                                                                 pInfo->pComment[realCpyFrameNum] = '\0';
3179                                                                                 /*string copy with '\0'*/
3180                                                                                 pInfo->commentLen = realCpyFrameNum;
3181                                                                                 _STRNCPY_EX(pInfo->pComment, pExtContent, pInfo->commentLen);
3182                                                                         }
3183                                                                 } else {
3184                                                                         pInfo->pComment = mmfile_string_convert((const char *)&pExtContent[tmp], realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->commentLen);
3185                                                                 }
3186                                                         } else {
3187 #ifdef __MMFILE_TEST_MODE__
3188                                                                 debug_msg("Description info too small to parse realCpyFrameNum(%d)\n", realCpyFrameNum);
3189 #endif
3190                                                         }
3191
3192                                                         tmp = 0;
3193
3194 #ifdef __MMFILE_TEST_MODE__
3195                                                         debug_msg("pInfo->pComment returned = (%s), pInfo->commentLen(%d)\n", pInfo->pComment, pInfo->commentLen);
3196 #endif
3197                                                         pInfo->tagV2Info.bDescriptionMarked = true;
3198                                                 } else if (strncmp((char *)CompTmp, "SYLT", 4) == 0 && pInfo->tagV2Info.bSyncLyricsMarked == false) {
3199                                                         int idx = 0;
3200                                                         int copy_len = 0;
3201                                                         int copy_start_pos = tmp;
3202                                                         AvSynclyricsInfo *synclyrics_info = NULL;
3203                                                         GList *synclyrics_info_list = NULL;
3204
3205                                                         if (realCpyFrameNum > 5) {
3206                                                                 realCpyFrameNum -= 5;
3207                                                                 tmp = 5;
3208
3209                                                                 if (textEncodingType == AV_ID3V2_UTF16 || textEncodingType == AV_ID3V2_UTF16_BE) {
3210                                                                         while ((NEWLINE_OF_UTF16(pExtContent + tmp) || NEWLINE_OF_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 4) {
3211                                                                                 realCpyFrameNum -= 4;
3212                                                                                 tmp += 4;
3213                                                                         }
3214
3215                                                                         if ((IS_ENCODEDBY_UTF16(pExtContent + tmp) || IS_ENCODEDBY_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 2) {
3216                                                                                 realCpyFrameNum -= 2;
3217                                                                                 tmp += 2;
3218                                                                                 textEncodingType = AV_ID3V2_UTF16;
3219                                                                         } else {
3220 #ifdef __MMFILE_TEST_MODE__
3221                                                                                 debug_msg("pInfo->pSyncLyrics Never Get Here!!\n");
3222 #endif
3223                                                                         }
3224                                                                 } else if (textEncodingType == AV_ID3V2_UTF8) {
3225                                                                         while (pExtContent[tmp] < 0x20 && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
3226                                                                                 realCpyFrameNum--;
3227                                                                                 tmp++;
3228                                                                         }
3229                                                                         textEncodingType = AV_ID3V2_UTF8;
3230                                                                 } else {
3231                                                                         while (pExtContent[tmp] < 0x20 && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
3232                                                                                 realCpyFrameNum--;
3233                                                                                 tmp++;
3234                                                                         }
3235                                                                         textEncodingType = AV_ID3V2_ISO_8859;
3236                                                                 }
3237
3238 #ifdef __MMFILE_TEST_MODE__
3239                                                                 debug_msg("tmp(%d) textEncodingType(%d), realCpyFrameNum(%d)\n", tmp, textEncodingType, realCpyFrameNum);
3240 #endif
3241
3242                                                                 if (realCpyFrameNum < MMFILE_SYNC_LYRIC_INFO_MIN_LEN) {
3243 #ifdef __MMFILE_TEST_MODE__
3244                                                                         debug_msg("failed to get Synchronised lyrics Info realCpyFramNum(%d)\n", realCpyFrameNum);
3245 #endif
3246                                                                         pInfo->syncLyricsNum = 0;
3247                                                                 } else {
3248                                                                         if (textEncodingType == AV_ID3V2_UTF16) {
3249                                                                                 debug_warning("[AV_ID3V2_UTF16] not implemented\n");
3250                                                                         } else if (textEncodingType == AV_ID3V2_UTF16_BE) {
3251                                                                                 debug_warning("[AV_ID3V2_UTF16_BE] not implemented\n");
3252                                                                         } else {
3253                                                                                 for (idx = 0; idx < realCpyFrameNum; idx++) {
3254                                                                                         if (pExtContent[tmp + idx] == 0x00) {
3255                                                                                                 synclyrics_info = (AvSynclyricsInfo *)malloc(sizeof(AvSynclyricsInfo));
3256
3257                                                                                                 if (textEncodingType == AV_ID3V2_UTF8) {
3258                                                                                                         synclyrics_info->lyric_info = mmfile_malloc(copy_len + 1);
3259                                                                                                         if (synclyrics_info->lyric_info) {
3260                                                                                                                 memset(synclyrics_info->lyric_info, 0, copy_len + 1);
3261                                                                                                                 memcpy(synclyrics_info->lyric_info, pExtContent + copy_start_pos, copy_len);
3262                                                                                                                 synclyrics_info->lyric_info[copy_len + 1] = '\0';
3263                                                                                                         }
3264                                                                                                 } else {
3265                                                                                                         synclyrics_info->lyric_info = mmfile_string_convert((const char *)&pExtContent[copy_start_pos], copy_len, "UTF-8", charset_array[textEncodingType], NULL, NULL);
3266                                                                                                 }
3267
3268                                                                                                 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];
3269                                                                                                 idx += 4;
3270                                                                                                 copy_start_pos = tmp + idx + 1;
3271 #ifdef __MMFILE_TEST_MODE__
3272                                                                                                 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);
3273 #endif
3274                                                                                                 copy_len = 0;
3275                                                                                                 synclyrics_info_list = g_list_append(synclyrics_info_list, synclyrics_info);
3276                                                                                         }
3277                                                                                         copy_len++;
3278                                                                                 }
3279                                                                                 pInfo->pSyncLyrics = synclyrics_info_list;
3280                                                                                 pInfo->syncLyricsNum = g_list_length(pInfo->pSyncLyrics);
3281                                                                         }
3282                                                                 }
3283                                                         } else {
3284 #ifdef __MMFILE_TEST_MODE__
3285                                                                 debug_msg("SyncLyrics info too small to parse realCpyFrameNum(%d)\n", realCpyFrameNum);
3286 #endif
3287                                                         }
3288
3289                                                         tmp = 0;
3290                                                         pInfo->tagV2Info.bSyncLyricsMarked = true;
3291                                                 } else if (strncmp((char *)CompTmp, "USLT", 4) == 0 && pInfo->tagV2Info.bUnsyncLyricsMarked == false) {
3292                                                         if (realCpyFrameNum > 3) {
3293                                                                 realCpyFrameNum -= 3;
3294                                                                 tmp = 3;
3295
3296                                                                 if (textEncodingType == AV_ID3V2_UTF16 || textEncodingType == AV_ID3V2_UTF16_BE) {
3297                                                                         while ((NEWLINE_OF_UTF16(pExtContent + tmp) || NEWLINE_OF_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 4) {
3298                                                                                 realCpyFrameNum -= 4;
3299                                                                                 tmp += 4;
3300                                                                         }
3301
3302                                                                         if ((IS_ENCODEDBY_UTF16(pExtContent + tmp) || IS_ENCODEDBY_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 2) {
3303                                                                                 realCpyFrameNum -= 2;
3304                                                                                 tmp += 2;
3305                                                                                 textEncodingType = AV_ID3V2_UTF16;
3306                                                                         } else {
3307 #ifdef __MMFILE_TEST_MODE__
3308                                                                                 debug_msg("pInfo->pUnsyncLyrics Never Get Here!!\n");
3309 #endif
3310                                                                         }
3311                                                                 } else if (textEncodingType == AV_ID3V2_UTF8) {
3312                                                                         while (pExtContent[tmp] < 0x20 && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
3313                                                                                 realCpyFrameNum--;
3314                                                                                 tmp++;
3315                                                                         }
3316                                                                         textEncodingType = AV_ID3V2_UTF8;
3317                                                                 } else {
3318                                                                         while (pExtContent[tmp] < 0x20 && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
3319                                                                                 realCpyFrameNum--;
3320                                                                                 tmp++;
3321                                                                         }
3322                                                                         textEncodingType = AV_ID3V2_ISO_8859;
3323                                                                 }
3324
3325 #ifdef __MMFILE_TEST_MODE__
3326                                                                 debug_msg("tmp(%d) textEncodingType(%d), realCpyFrameNum(%d)\n", tmp, textEncodingType, realCpyFrameNum);
3327 #endif
3328
3329                                                                 if (textEncodingType == AV_ID3V2_UTF8) {
3330                                                                         pInfo->pUnsyncLyrics = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3331
3332                                                                         if (pInfo->pUnsyncLyrics != NULL) {
3333                                                                                 memset(pInfo->pUnsyncLyrics, 0, (realCpyFrameNum + 2));
3334                                                                                 memcpy(pInfo->pUnsyncLyrics, pExtContent + tmp, realCpyFrameNum);
3335                                                                                 pInfo->pUnsyncLyrics[realCpyFrameNum] = '\0';
3336                                                                                 /*string copy with '\0'*/
3337                                                                                 pInfo->unsynclyricsLen = realCpyFrameNum;
3338                                                                                 _STRNCPY_EX(pInfo->pUnsyncLyrics, pExtContent, pInfo->unsynclyricsLen);
3339                                                                         } else {
3340                                                                                 debug_error("out of memoryu for SyncLyrics\n");
3341                                                                         }
3342                                                                 } else {
3343                                                                         pInfo->pUnsyncLyrics = mmfile_string_convert((const char *)&pExtContent[tmp], realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->unsynclyricsLen);
3344                                                                 }
3345                                                         } else {
3346 #ifdef __MMFILE_TEST_MODE__
3347                                                                 debug_msg("Description info too small to parse realCpyFrameNum(%d)\n", realCpyFrameNum);
3348 #endif
3349                                                         }
3350
3351                                                         tmp = 0;
3352
3353 #ifdef __MMFILE_TEST_MODE__
3354                                                         debug_msg("pInfo->pUnsyncLyrics returned = (%s), pInfo->unsynclyricsLen(%d)\n", pInfo->pUnsyncLyrics, pInfo->unsynclyricsLen);
3355 #endif
3356                                                         pInfo->tagV2Info.bDescriptionMarked = true;
3357                                                 } else if (strncmp((char *)CompTmp, "TCON", 4) == 0 && pInfo->tagV2Info.bGenreMarked == false) {
3358                                                         if (textEncodingType == AV_ID3V2_UTF8) {
3359                                                                 pInfo->pGenre = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3360                                                                 if (pInfo->pGenre) {
3361                                                                         memcpy(pInfo->pGenre, pExtContent, realCpyFrameNum);
3362                                                                         pInfo->pGenre[realCpyFrameNum] = '\0';
3363                                                                         /*string copy with '\0'*/
3364                                                                         pInfo->genreLen = realCpyFrameNum;
3365                                                                         _STRNCPY_EX(pInfo->pGenre, pExtContent, pInfo->genreLen);
3366                                                                 }
3367                                                         } else {
3368                                                                 pInfo->pGenre = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->genreLen);
3369                                                         }
3370
3371 #ifdef __MMFILE_TEST_MODE__
3372                                                         debug_msg("pInfo->pGenre returned = (%s), pInfo->genreLen(%d)\n", pInfo->pGenre, pInfo->genreLen);
3373 #endif
3374
3375                                                         if ((pInfo->pGenre != NULL) && (pInfo->genreLen > 0)) {
3376                                                                 bool ret = FALSE;
3377                                                                 int int_genre = -1;
3378
3379                                                                 ret = is_numeric(pInfo->pGenre, pInfo->genreLen);
3380
3381                                                                 if (ret == TRUE) {
3382                                                                         sscanf(pInfo->pGenre, "%d", &int_genre);
3383 #ifdef __MMFILE_TEST_MODE__
3384                                                                         debug_msg("genre information is inteager [%d]\n", int_genre);
3385 #endif
3386
3387                                                                         /*Change int to string */
3388                                                                         if ((0 <= int_genre) && (int_genre < GENRE_COUNT - 1)) {
3389                                                                                 /*save genreinfo like "(123)". mm_file_id3tag_restore_content_info convert it to string*/
3390                                                                                 char tmp_genre[6] = {0, };      /*ex. "(123)+NULL"*/
3391                                                                                 int tmp_genre_len = 0;
3392
3393                                                                                 memset(tmp_genre, 0, 6);
3394                                                                                 snprintf(tmp_genre, sizeof(tmp_genre), "(%d)", int_genre);
3395
3396                                                                                 tmp_genre_len = strlen(tmp_genre);
3397                                                                                 if (tmp_genre_len > 0) {
3398                                                                                         if (pInfo->pGenre) _FREE_EX(pInfo->pGenre);
3399                                                                                         pInfo->pGenre = mmfile_malloc(sizeof(char) * (tmp_genre_len + 1));
3400                                                                                         if (pInfo->pGenre) {
3401                                                                                                 strncpy(pInfo->pGenre, tmp_genre, tmp_genre_len);
3402                                                                                                 pInfo->pGenre[tmp_genre_len] = 0;
3403                                                                                         }
3404                                                                                 }
3405                                                                         }
3406                                                                 }
3407                                                         }
3408
3409                                                         pInfo->tagV2Info.bGenreMarked = true;
3410                                                 } else if (strncmp((char *)CompTmp, "TRCK", 4) == 0 && pInfo->tagV2Info.bTrackNumMarked == false) {
3411                                                         if (textEncodingType == AV_ID3V2_UTF8) {
3412                                                                 pInfo->pTrackNum = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3413                                                                 if (pInfo->pTrackNum != NULL) {
3414                                                                         memcpy(pInfo->pTrackNum, pExtContent, realCpyFrameNum);
3415                                                                         pInfo->pTrackNum[realCpyFrameNum] = '\0';
3416                                                                         /*string copy with '\0'*/
3417                                                                         pInfo->tracknumLen = realCpyFrameNum;
3418                                                                         _STRNCPY_EX(pInfo->pTrackNum, pExtContent, pInfo->tracknumLen);
3419                                                                 }
3420                                                         } else {
3421                                                                 pInfo->pTrackNum = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->tracknumLen);
3422                                                         }
3423
3424
3425 #ifdef __MMFILE_TEST_MODE__
3426                                                         debug_msg("pInfo->pTrackNum returned = (%s), pInfo->tracknumLen(%d)\n", pInfo->pTrackNum, pInfo->tracknumLen);
3427 #endif
3428                                                         pInfo->tagV2Info.bTrackNumMarked = true;
3429                                                 } else if (strncmp((char *)CompTmp, "TENC", 4) == 0 && pInfo->tagV2Info.bEncByMarked == false) {
3430                                                         if (textEncodingType == AV_ID3V2_UTF8) {
3431                                                                 pInfo->pEncBy = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3432                                                                 if (pInfo->pEncBy != NULL) {
3433                                                                         memcpy(pInfo->pEncBy, pExtContent, realCpyFrameNum);
3434                                                                         pInfo->pEncBy[realCpyFrameNum] = '\0';
3435                                                                         /*string copy with '\0'*/
3436                                                                         pInfo->encbyLen = realCpyFrameNum;
3437                                                                         _STRNCPY_EX(pInfo->pEncBy, pExtContent, pInfo->encbyLen);
3438                                                                 }
3439                                                         } else {
3440                                                                 pInfo->pEncBy = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->encbyLen);
3441                                                         }
3442
3443 #ifdef __MMFILE_TEST_MODE__
3444                                                         debug_msg("pInfo->pEncBy returned = (%s), pInfo->encbyLen(%d)\n", pInfo->pEncBy, pInfo->encbyLen);
3445 #endif
3446                                                         pInfo->tagV2Info.bEncByMarked = true;
3447                                                 } else if (strncmp((char *)CompTmp, "WXXX", 4) == 0 && pInfo->tagV2Info.bURLMarked == false) {
3448                                                         if (textEncodingType == AV_ID3V2_UTF8) {
3449                                                                 pInfo->pURL = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3450                                                                 if (pInfo->pURL != NULL) {
3451                                                                         memcpy(pInfo->pURL, pExtContent, realCpyFrameNum);
3452                                                                         pInfo->pURL[realCpyFrameNum] = '\0';
3453                                                                         /*string copy with '\0'*/
3454                                                                         pInfo->urlLen = realCpyFrameNum;
3455                                                                         _STRNCPY_EX(pInfo->pURL, pExtContent, pInfo->urlLen);
3456                                                                 }
3457                                                         } else {
3458                                                                 pInfo->pURL = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->urlLen);
3459                                                         }
3460
3461 #ifdef __MMFILE_TEST_MODE__
3462                                                         debug_msg("pInfo->pURL returned = (%s), pInfo->urlLen(%d)\n", pInfo->pURL, pInfo->urlLen);
3463 #endif
3464                                                         pInfo->tagV2Info.bURLMarked = true;
3465                                                 } else if (strncmp((char *)CompTmp, "TCOP", 4) == 0 && pInfo->tagV2Info.bCopyRightMarked == false) {
3466                                                         if (textEncodingType == AV_ID3V2_UTF8) {
3467                                                                 pInfo->pCopyright = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3468                                                                 if (pInfo->pCopyright != NULL) {
3469                                                                         memcpy(pInfo->pCopyright, pExtContent, realCpyFrameNum);
3470                                                                         pInfo->pCopyright[realCpyFrameNum] = '\0';
3471                                                                         /*string copy with '\0'*/
3472                                                                         pInfo->copyrightLen = realCpyFrameNum;
3473                                                                         _STRNCPY_EX(pInfo->pCopyright, pExtContent, pInfo->copyrightLen);
3474                                                                 }
3475                                                         } else {
3476                                                                 pInfo->pCopyright = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->copyrightLen);
3477                                                         }
3478
3479 #ifdef __MMFILE_TEST_MODE__
3480                                                         debug_msg("pInfo->pCopyright returned = (%s), pInfo->copyrightLen(%d)\n", pInfo->pCopyright, pInfo->copyrightLen);
3481 #endif
3482                                                         pInfo->tagV2Info.bCopyRightMarked = true;
3483                                                 } else if (strncmp((char *)CompTmp, "TOPE", 4) == 0 && pInfo->tagV2Info.bOriginArtistMarked == false) {
3484                                                         if (textEncodingType == AV_ID3V2_UTF8) {
3485                                                                 pInfo->pOriginArtist = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3486                                                                 if (pInfo->pOriginArtist != NULL) {
3487                                                                         memcpy(pInfo->pOriginArtist, pExtContent, realCpyFrameNum);
3488                                                                         pInfo->pOriginArtist[realCpyFrameNum] = '\0';
3489                                                                         /*string copy with '\0'*/
3490                                                                         pInfo->originartistLen = realCpyFrameNum;
3491                                                                         _STRNCPY_EX(pInfo->pOriginArtist, pExtContent, pInfo->originartistLen);
3492                                                                 }
3493                                                         } else {
3494                                                                 pInfo->pOriginArtist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->originartistLen);
3495                                                         }
3496
3497 #ifdef __MMFILE_TEST_MODE__
3498                                                         debug_msg("pInfo->pOriginArtist returned = (%s), pInfo->originartistLen(%d)\n", pInfo->pOriginArtist, pInfo->originartistLen);
3499 #endif
3500                                                         pInfo->tagV2Info.bOriginArtistMarked = true;
3501                                                 } else if (strncmp((char *)CompTmp, "TCOM", 4) == 0 && pInfo->tagV2Info.bComposerMarked == false) {
3502                                                         if (textEncodingType == AV_ID3V2_UTF8) {
3503                                                                 pInfo->pComposer = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3504                                                                 if (pInfo->pComposer != NULL) {
3505                                                                         memcpy(pInfo->pComposer, pExtContent, realCpyFrameNum);
3506                                                                         pInfo->pComposer[realCpyFrameNum] = '\0';
3507                                                                         /*string copy with '\0'*/
3508                                                                         pInfo->composerLen = realCpyFrameNum;
3509                                                                         _STRNCPY_EX(pInfo->pComposer, pExtContent, pInfo->composerLen);
3510                                                                 }
3511                                                         } else {
3512                                                                 pInfo->pComposer = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->composerLen);
3513                                                         }
3514
3515 #ifdef __MMFILE_TEST_MODE__
3516                                                         debug_msg("pInfo->pComposer returned = (%s), pInfo->originartistLen(%d)\n", pInfo->pComposer, pInfo->composerLen);
3517 #endif
3518                                                         pInfo->tagV2Info.bComposerMarked = true;
3519                                                 } else if (strncmp((char *)CompTmp, "TDRC", 4) == 0 && pInfo->tagV2Info.bRecDateMarked == false) {      /*TYER(year) and TRDA are replaced by the TDRC */
3520                                                         if (textEncodingType == AV_ID3V2_UTF8) {
3521                                                                 pInfo->pRecDate = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3522                                                                 if (pInfo->pRecDate != NULL) {
3523                                                                         memcpy(pInfo->pRecDate, pExtContent, realCpyFrameNum);
3524                                                                         pInfo->pRecDate[realCpyFrameNum] = '\0';
3525                                                                         /*string copy with '\0'*/
3526                                                                         pInfo->recdateLen = realCpyFrameNum;
3527                                                                         _STRNCPY_EX(pInfo->pRecDate, pExtContent, pInfo->recdateLen);
3528                                                                 }
3529                                                         } else {
3530                                                                 pInfo->pRecDate = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->recdateLen);
3531                                                         }
3532
3533 #ifdef __MMFILE_TEST_MODE__
3534                                                         debug_msg("pInfo->pRecDate returned = (%s), pInfo->recdateLen(%d)\n", pInfo->pRecDate, pInfo->recdateLen);
3535 #endif
3536                                                         pInfo->tagV2Info.bRecDateMarked = true;
3537                                                 } else if (strncmp((char *)CompTmp, "TIT1", 4) == 0 && pInfo->tagV2Info.bContentGroupMarked == false) {
3538                                                         if (textEncodingType == AV_ID3V2_UTF8) {
3539                                                                 pInfo->pContentGroup = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3540                                                                 if (pInfo->pContentGroup != NULL) {
3541                                                                         memcpy(pInfo->pContentGroup, pExtContent, realCpyFrameNum);
3542                                                                         pInfo->pContentGroup[realCpyFrameNum] = '\0';
3543                                                                         /*string copy with '\0'*/
3544                                                                         pInfo->contentGroupLen = realCpyFrameNum;
3545                                                                         _STRNCPY_EX(pInfo->pContentGroup, pExtContent, pInfo->contentGroupLen);
3546                                                                 }
3547                                                         } else {
3548                                                                 pInfo->pContentGroup = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->contentGroupLen);
3549                                                         }
3550 #ifdef __MMFILE_TEST_MODE__
3551                                                         debug_msg("pInfo->pContentGroup returned = (%s), pInfo->contentGroupLen(%d)\n", pInfo->pContentGroup, pInfo->contentGroupLen);
3552 #endif
3553                                                         pInfo->tagV2Info.bContentGroupMarked = true;
3554                                                 } else if (strncmp((char *)CompTmp, "APIC", 4) == 0 && pInfo->tagV2Info.bImageMarked == false && realCpyFrameNum <= 2000000) {
3555                                                         if (pExtContent[0] != '\0') {
3556                                                                 for (inx = 0; inx < MP3_ID3_IMAGE_MIME_TYPE_MAX_LENGTH - 1; inx++)
3557                                                                         pInfo->imageInfo.imageMIMEType[inx] = '\0';/*ini mimetype variable */
3558
3559                                                                 while ((checkImgMimeTypeMax < MP3_ID3_IMAGE_MIME_TYPE_MAX_LENGTH - 1) && pExtContent[checkImgMimeTypeMax] != '\0') {
3560                                                                         pInfo->imageInfo.imageMIMEType[checkImgMimeTypeMax] = pExtContent[checkImgMimeTypeMax];
3561                                                                         checkImgMimeTypeMax++;
3562                                                                 }
3563                                                                 pInfo->imageInfo.imgMimetypeLen = checkImgMimeTypeMax;
3564                                                         } else {
3565                                                                 pInfo->imageInfo.imgMimetypeLen = 0;
3566                                                         }
3567
3568                                                         imgstartOffset += checkImgMimeTypeMax;
3569
3570                                                         if (strncmp(pInfo->imageInfo.imageMIMEType, MIME_PRFIX, strlen(MIME_PRFIX)) != 0) {
3571                                                                 pInfo->imageInfo.imgMimetypeLen = 0;
3572                                                                 debug_error("APIC NOT VALID");
3573                                                                 continue;
3574                                                         }
3575
3576                                                         if ((pExtContent[imgstartOffset] == '\0') && (realCpyFrameNum - imgstartOffset > 0)) {
3577                                                                 imgstartOffset++;/*endofMIME(1byte) */
3578
3579                                                                 if (pExtContent[imgstartOffset] < AV_ID3V2_PICTURE_TYPE_MAX) {
3580                                                                         pInfo->imageInfo.pictureType = pExtContent[imgstartOffset];
3581                                                                 }
3582                                                                 imgstartOffset++;/*PictureType(1byte) */
3583
3584                                                                 if (pExtContent[imgstartOffset] != 0x0) {
3585                                                                         int cur_pos = 0;
3586                                                                         int dis_len = 0;
3587                                                                         int new_dis_len = 0;
3588                                                                         char *tmp_desc = NULL;
3589
3590                                                                         while (1) {
3591                                                                                 if (pExtContent[imgstartOffset + cur_pos] == '\0') {
3592                                                                                         if (realCpyFrameNum < imgstartOffset + cur_pos) {
3593                                                                                                 debug_error("End of APIC Tag %d %d %d\n", realCpyFrameNum, imgstartOffset, cur_pos);
3594                                                                                                 break;
3595                                                                                         }
3596                                                                                         /*check end of image description*/
3597                                                                                         if ((pExtContent[imgstartOffset + cur_pos + 1] == gTagJPEGHeader[0]) ||
3598                                                                                             (pExtContent[imgstartOffset + cur_pos + 1] == gTagPNGHeader[0])) {
3599 #ifdef __MMFILE_TEST_MODE__
3600                                                                                                 debug_msg("length of description (%d)", cur_pos);
3601 #endif
3602
3603                                                                                                 break;
3604                                                                                         }
3605                                                                                 }
3606                                                                                 cur_pos++;
3607                                                                         }
3608
3609                                                                         dis_len = cur_pos + 1;
3610
3611                                                                         tmp_desc = mmfile_malloc(sizeof(char) * dis_len);
3612
3613                                                                         if (tmp_desc != NULL) {
3614                                                                                 memcpy(tmp_desc, pExtContent + imgstartOffset, dis_len);
3615                                                                                 debug_msg("tmp_desc %s\n", tmp_desc);
3616
3617                                                                                 /*convert description*/
3618                                                                                 pInfo->imageInfo.imageDescription = mmfile_string_convert(tmp_desc, dis_len, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&new_dis_len);
3619                                                                                 debug_msg("new_desc %s(%d)\n", pInfo->imageInfo.imageDescription, new_dis_len);
3620                                                                                 mmfile_free(tmp_desc);
3621
3622                                                                                 pInfo->imageInfo.imgDesLen = new_dis_len; /**/
3623                                                                         }
3624
3625                                                                         imgstartOffset += cur_pos;
3626                                                                 } else {
3627                                                                         pInfo->imageInfo.imgDesLen = 0;
3628                                                                 }
3629
3630                                                                 if ((pExtContent[imgstartOffset] == '\0') && (realCpyFrameNum - imgstartOffset > 0)) {
3631                                                                         imgstartOffset++; /* endofDesceriptionType(1byte) */
3632
3633                                                                         while (pExtContent[imgstartOffset] == '\0') {   /*some content has useless '\0' in front of picture data */
3634                                                                                 imgstartOffset++;
3635                                                                         }
3636
3637 #ifdef __MMFILE_TEST_MODE__
3638                                                                         debug_msg("after scaning imgDescription imgstartOffset(%d) value!\n", imgstartOffset);
3639 #endif
3640
3641                                                                         if (realCpyFrameNum - imgstartOffset > 0) {
3642                                                                                 pInfo->imageInfo.imageLen = realCpyFrameNum - imgstartOffset;
3643                                                                                 pInfo->imageInfo.pImageBuf = mmfile_malloc(pInfo->imageInfo.imageLen + 1);
3644
3645                                                                                 if (pInfo->imageInfo.pImageBuf != NULL) {
3646                                                                                         memcpy(pInfo->imageInfo.pImageBuf, pExtContent + imgstartOffset, pInfo->imageInfo.imageLen);
3647                                                                                         pInfo->imageInfo.pImageBuf[pInfo->imageInfo.imageLen] = 0;
3648                                                                                 }
3649
3650                                                                                 if (IS_INCLUDE_URL(pInfo->imageInfo.imageMIMEType))
3651                                                                                         pInfo->imageInfo.bURLInfo = true; /*if mimetype is "-->", image date has an URL */
3652                                                                         } else {
3653 #ifdef __MMFILE_TEST_MODE__
3654                                                                                 debug_msg("No APIC image!! realCpyFrameNum(%d) - imgstartOffset(%d)\n", realCpyFrameNum, imgstartOffset);
3655 #endif
3656                                                                         }
3657                                                                 }
3658                                                         }
3659
3660                                                         checkImgMimeTypeMax = 0;
3661                                                         inx = 0;
3662                                                         imgstartOffset = 0;
3663                                                         pInfo->tagV2Info.bImageMarked = true;
3664                                                 } else {
3665 #ifdef __MMFILE_TEST_MODE__
3666                                                         debug_msg("CompTmp(%s) This Frame ID currently not Supports!!\n", CompTmp);
3667 #endif
3668                                                 }
3669                                         }
3670
3671                                 } else {
3672 #ifdef __MMFILE_TEST_MODE__
3673                                         debug_msg("mmf_file_id3tag_parse_v224: All of the pExtContent Values are NULL\n");
3674 #endif
3675                                 }
3676
3677                         } else {
3678                                 curPos += purelyFramelen;
3679                                 if (purelyFramelen != 0)
3680                                         needToloopv2taglen = MP3_TAGv2_23_TXT_HEADER_LEN;
3681                         }
3682
3683                         if (pExtContent)        _FREE_EX(pExtContent);
3684                         memset(CompTmp, 0, 4);
3685                         if (curPos < taglen) {
3686                                 needToloopv2taglen -= oneFrameLen;
3687                                 v2numOfFrames++;
3688                         } else
3689                                 needToloopv2taglen = MP3_TAGv2_23_TXT_HEADER_LEN;
3690
3691                         oneFrameLen = 0;
3692                         encodingOffSet = 0;
3693                         realCpyFrameNum = 0;
3694                         textEncodingType = 0;
3695                         purelyFramelen = 0;
3696
3697                 }
3698         }
3699
3700         release_characterset_array(charset_array);
3701
3702         if (taglen)
3703                 return true;
3704         else
3705                 return false;
3706
3707 }
3708
3709 EXPORT_API
3710 void mm_file_id3tag_restore_content_info(AvFileContentInfo *pInfo)
3711 {
3712         char    *mpegAudioGenre = NULL/*, *tmpGenreForV1Tag = NULL*/;
3713         bool    bAdditionGenre = false /*, bMpegAudioFrame = false*/;
3714         int mpegAudioFileLen = 0, idv2IntGenre = 148/*, tmpinx = 0, tmpinx2=0*/;
3715 #ifdef _SM_ONLY
3716         char    *pGenreForUTF16;
3717 #endif
3718         unsigned char genre = pInfo->genre;
3719
3720         /* for Genre Info */
3721         if (pInfo->tagV2Info.bGenreMarked == false) {
3722                 if (pInfo->bV1tagFound == true) {
3723 #ifdef __MMFILE_TEST_MODE__
3724                         debug_msg("Genre: %d\n", genre);
3725 #endif
3726                         if (genre > 147)
3727                                 genre = 148;
3728
3729                         if (MpegAudio_Genre[genre] != NULL) {
3730                                 pInfo->genreLen = strlen(MpegAudio_Genre[genre]);
3731                                 if (pInfo->genreLen > 0) {
3732                                         /* Give space for NULL character. Hence added "+1" */
3733                                         pInfo->pGenre = mmfile_malloc(sizeof(char) * (pInfo->genreLen + 1));
3734                                         if (pInfo->pGenre) {
3735                                                 strncpy(pInfo->pGenre, MpegAudio_Genre[genre], pInfo->genreLen);
3736                                                 pInfo->pGenre[pInfo->genreLen] = '\0';
3737                                         }
3738                                 }
3739                         }
3740                 } else {
3741 #ifdef __MMFILE_TEST_MODE__
3742                         debug_msg("Genre was not Found.\n");
3743 #endif
3744                 }
3745         } else if (pInfo->tagV2Info.bGenreMarked == true) {
3746                 if (pInfo->genreLen && pInfo->tagV2Info.bGenreUTF16) {
3747                         pInfo->pGenre[pInfo->genreLen + 1] = '\0';
3748                         mpegAudioGenre = mmfile_malloc(sizeof(char) * (pInfo->genreLen * AV_WM_LOCALCODE_SIZE_MAX + 1));
3749 #ifdef _SM_ONLY
3750                         pGenreForUTF16 = (char *)pInfo->pGenre;
3751
3752                         if (WmConvert2LCode(mpegAudioGenre, sizeof(char) * AV_WM_LOCALCODE_SIZE_MAX * (pInfo->genreLen + 1), pGenreForUTF16)) {
3753                                 pInfo->genreLen = strlen(mpegAudioGenre);
3754                                 mpegAudioGenre[pInfo->genreLen] = '\0';
3755                         }
3756 #endif
3757                 } else {
3758 #ifdef __MMFILE_TEST_MODE__
3759                         debug_msg("pInfo->genreLen size is Zero Or not UTF16 code! genreLen[%d] genre[%s]\n", pInfo->genreLen, pInfo->pGenre);
3760 #endif
3761                         if (pInfo->pGenre) {
3762                                 pInfo->genreLen = strlen(pInfo->pGenre);
3763                                 mpegAudioGenre = mmfile_malloc(sizeof(char) * (pInfo->genreLen + 1));
3764                                 if (mpegAudioGenre != NULL) {
3765                                         mpegAudioGenre[pInfo->genreLen] = '\0';
3766                                         strncpy(mpegAudioGenre, pInfo->pGenre, pInfo->genreLen);
3767                                 }
3768                         } else {
3769                                 pInfo->genreLen = 0;
3770                         }
3771                 }
3772
3773                 if (pInfo->pGenre) _FREE_EX(pInfo->pGenre);
3774
3775                 /*tmpinx = 0;*/
3776                 if (mpegAudioGenre != NULL) {
3777                         /**
3778                          *Genre number
3779                          * (XXX)        XXX is 0 - 148
3780                          */
3781                         pInfo->genreLen = strlen(mpegAudioGenre);
3782                         if (pInfo->genreLen >= 3 &&
3783                             mpegAudioGenre[0] == '(' && mpegAudioGenre[pInfo->genreLen - 1] == ')') {
3784                                 bAdditionGenre = true;
3785                                 for (mpegAudioFileLen = 1; mpegAudioFileLen <= pInfo->genreLen - 2; mpegAudioFileLen++) {
3786                                         if (mpegAudioGenre[mpegAudioFileLen] < '0' || mpegAudioGenre[mpegAudioFileLen] > '9') {
3787                                                 bAdditionGenre = false;
3788                                                 break;
3789                                         }
3790                                 }
3791                         }
3792
3793                         if (bAdditionGenre == true) {
3794                                 idv2IntGenre = atoi(mpegAudioGenre + 1);
3795
3796                                 if (idv2IntGenre > 147 || idv2IntGenre < 0)
3797                                         idv2IntGenre = 148;
3798
3799                                 if (MpegAudio_Genre[idv2IntGenre] != NULL) {
3800                                         pInfo->genreLen = strlen(MpegAudio_Genre[idv2IntGenre]);
3801                                         if (pInfo->genreLen > 0) {
3802                                                 /* Give space for NULL character. Hence added "+1" */
3803                                                 pInfo->pGenre = mmfile_malloc(sizeof(char) * (pInfo->genreLen + 1));
3804                                                 if (pInfo->pGenre) {
3805                                                         strncpy(pInfo->pGenre, MpegAudio_Genre[idv2IntGenre], pInfo->genreLen);
3806                                                         pInfo->pGenre[pInfo->genreLen] = 0;
3807                                                 }
3808                                         }
3809                                 }
3810 #ifdef __MMFILE_TEST_MODE__
3811                                 debug_msg("pInfo->pGenre = %s\n", pInfo->pGenre);
3812 #endif
3813                         } else if (bAdditionGenre == false && pInfo->genreLen > 0) {
3814                                 /**
3815                                  * Genre string.
3816                                  */
3817
3818                                 /* Give space for NULL character. Hence added "+1" */
3819                                 pInfo->pGenre = mmfile_malloc(sizeof(char) * (pInfo->genreLen + 1));
3820                                 if (pInfo->pGenre) {
3821                                         strncpy(pInfo->pGenre, mpegAudioGenre, pInfo->genreLen);
3822                                         pInfo->pGenre[pInfo->genreLen] = '\0';
3823                                 }
3824 #ifdef __MMFILE_TEST_MODE__
3825                                 debug_msg("pInfo->pGenre = %s, pInfo->genreLen = %d\n", pInfo->pGenre, pInfo->genreLen);
3826 #endif
3827                         } else {
3828 #ifdef __MMFILE_TEST_MODE__
3829                                 debug_msg("Failed to \"(...)\" value to genre = %s\n", pInfo->pGenre);
3830 #endif
3831                         }
3832                 } else {
3833 #ifdef __MMFILE_TEST_MODE__
3834                         debug_msg("mpegAudioGenre = %x\n", mpegAudioGenre);
3835 #endif
3836                 }
3837                 if (mpegAudioGenre)
3838                         _FREE_EX(mpegAudioGenre);
3839
3840         } else {
3841 #ifdef __MMFILE_TEST_MODE__
3842                 debug_msg("Neither ID3 v1 nor v2 info doesn't have Genre Info.\n");
3843 #endif
3844         }
3845
3846 }
3847
3848 void mm_file_free_synclyrics_list(GList *synclyrics_list)
3849 {
3850         int list_len = 0;
3851         int idx = 0;
3852         AvSynclyricsInfo *synclyrics_info = NULL;
3853
3854         if (synclyrics_list == NULL) {
3855                 return;
3856         }
3857
3858         list_len = g_list_length(synclyrics_list);
3859         for (idx = 0; idx < list_len; idx++) {
3860                 synclyrics_info = g_list_nth_data(synclyrics_list, idx);
3861
3862                 if (synclyrics_info != NULL) {
3863                         mmfile_free(synclyrics_info->lyric_info);
3864                         mmfile_free(synclyrics_info);
3865                 }
3866         }
3867
3868         if (synclyrics_list != NULL) {
3869                 g_list_free(synclyrics_list);
3870                 synclyrics_list = NULL;
3871         }
3872
3873         return;
3874 }
3875