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