/*****************************************************************************
 * Module    : Music
 * File      : music_ID3.c
 * Author    : Hanny
 * Email     : coldney@yahoo.com.cn
 * Function  : 音乐获取ID3信息
 *****************************************************************************/
#include "include.h"
#include "music_ID3.h"
#include "task_music.h"

#if MP3_ID3_EN
extern FIL fat_file, fat_file_opt;
extern FATFS fat_fs;
extern void id3_info_transfer(u8 label_len,u8 *buf,u8 max_len,u8 unicode_flag);

#define ID3_DATA_LEN  200

#define ID3_FLAG  (ID3_DATA_LEN - 1)
IAR_XDATA_A u8 music_ID3_buff[1024]  @ "MUSIC_ID3BUFF";
IAR_XDATA_A u8 id3_buff_temp[100] @ "MUSIC_ID3BUFF";
IAR_XDATA_A u8 id3_title[31] @ "ID3_BUFF";
IAR_XDATA_A u8 id3_artist[31] @ "ID3_BUFF";
IAR_XDATA_A u8 id3_album[41] @ "ID3_BUFF";

IAR_XDATA_A type_msc_ID3 msc_ID3 @ "MUSIC_ID3BUFF";


//WMA ASF 标准帧头信息
#pragma location="MUSIC_ID3_TBL"
IAR_CONST u8 ff_asf_comment_header[16] = {
    0x33, 0x26, 0xb2, 0x75, 0x8E, 0x66, 0xCF, 0x11, 0xa6, 0xd9, 0x00, 0xaa, 0x00, 0x62, 0xce, 0x6c
};
IAR_CONST u8 ff_asf_exinfo_comment_header[16] = {
    0x40, 0xA4, 0xD0, 0xD2, 0x07, 0xE3, 0xD2, 0x11, 0x97, 0xF0, 0x00, 0xA0, 0xC9, 0x5E, 0xA8, 0x50
};
IAR_CONST u8 wma_album_title[0x19] = {
    0x57, 0x00,0x4d,0x00,0x2f,0x00,0x41,0x00,0x6c,0x00,0x62,0x00,0x75,0x00,0x6d,0x00,0x54,0x00,0x69,0x00,0x74,0x00,0x6c,0x00,0x65
};


IAR_CONST u8 wav_comment_header[][4] = {
    {'L', 'I', 'S', 'T'},
    {'I', 'N', 'F', 'O'},
    {'I', 'N', 'A', 'M'},
    {'I', 'A', 'R', 'T'},
    {'I', 'P', 'R', 'D'},
};

IAR_CONST char ID3_TBL[3][5]={
  "TPE1",//作者
  "TALB",//专辑
  "TIT2"
};
#pragma constseg=default

//比较两个字符串是否相等，相等为1，否则为0，
#pragma location="MUSIC_ID3_SEG_1"
bool str_memcmp(void *str1, void __code *str2, u8 len)
{
    u8 *ptr1 = (u8 *)str1;
    u8 __code *ptr2 = (u8 __code *)str2;
    u8 i;
    for (i=0; i<len; i++) {
        if (*ptr1++ != *ptr2++) {
            return false;
        }
    }
    return true;
}

//获取4byte长度，order_flag=0为倒序，order_flag=1为顺序
#pragma location="MUSIC_ID3_SEG_1"
u32 get_data32(u8 *buff, u8 order_flag)
{
    if (order_flag) {
        return ((u32)buff[0]<<24) | ((u32)buff[1]<<16) | ((u32)buff[2]<<8) | (buff[3]<<0);
    } else {
        return ((u32)buff[3]<<24) | ((u32)buff[2]<<16) | ((u32)buff[1]<<8) | (buff[0]<<0);
    }
}

//获取WAV INFO
#pragma location="MUSIC_ID3_SEG_2"
bool wav_get_info(void)
{
    u8 *ptr_start, *ptr_end, flag = 0;
    u32 len, sec, surplus, size;
    u8 *buff_ptr = music_ID3_buff;

    music_clear_ID3();

    len = fat_file.fsize + 1;
    sec = (u32)(len / fat_fs.s_size);
    surplus = len - sec * fat_fs.s_size;
    //printf("len=%ld sec=%ld\n", len, sec);
    //printf("sur=%ld\n", surplus);;

    f_seek_opt(0, sec-1);
    f_read_opt(buff_ptr);
    f_read_opt(buff_ptr+512);   //读1024byte
    ptr_start = buff_ptr;
    ptr_end = buff_ptr + 512 + surplus;
    while (ptr_start < ptr_end) {
        if (str_memcmp(ptr_start, (void __code*)wav_comment_header[0], 4)) {  //LIST
            flag = 1;
            break;
        }else {
            flag = 0;
        }
        ptr_start += 4;
    }
    if (!flag) {
        goto ID3_ERR;
    }
    //printf("list ok\n");
    flag = 0;
    ptr_start += 4;
    /*
    for (i=0; i<4; i++) {
        printf("%02x ", ptr_start[i]);
    }
    printf("\n");*/
    size = get_data32(ptr_start, 0);
    if (size < 4) {  //list tag不能小于4byte
        goto ID3_ERR;
    }
    ptr_start += 4;
    if(size+ptr_start<ptr_end)
        ptr_end = size+ptr_start;
    //printf("size=%08lx\n", size);
    while (ptr_start < ptr_end) {
        if (str_memcmp(ptr_start, (void __code*)wav_comment_header[1], 4)) {  //INFO
            flag = 1;
            break;
        }else {
            flag = 0;
        }
        ptr_start += 4;
    }
    //printf("info ok\n");
    if (!flag) {
        goto ID3_ERR;
    }
    flag = 0;
    ptr_start += 4;
    while (ptr_start < ptr_end) {
        if (str_memcmp(ptr_start, (void __code*)wav_comment_header[2], 4)) {  //INAM
            flag = 1;
            break;
        }else {
            flag = 0;
        }
        ptr_start += 4;
    }
    //printf("inam ok\n");
    if (!flag) {
        goto ID3_ERR;
    }
    flag = 0;
    ptr_start += 4;
    if(ptr_start+5 < ptr_end)
    {
        size = get_data32(ptr_start, 0);
        if (!size) {
            goto ID3_ERR;
        }
        ptr_start += 4;
        if(ptr_start+size>ptr_end)
            sec = ptr_end - ptr_start;
        if(sec>31)
            sec = 31;
        memcpy(id3_title, ptr_start, sec-1);
    }
    else
        goto ID3_ERR;

    ptr_start += size;
    if(*ptr_start == 0)
        ptr_start++;


    while (ptr_start < ptr_end) {
        if (str_memcmp(ptr_start, (void __code*)wav_comment_header[3], 4)) {  //IART
            flag = 1;
            break;
        }else {
            flag = 0;
        }
        ptr_start += 4;
    }
    if(!flag)
        goto ID3_ERR;
    flag = 0;
    ptr_start += 4;
    if(ptr_start+5 < ptr_end)
    {
        size = get_data32(ptr_start, 0);
        if (!size) {
            goto ID3_ERR;
        }
        ptr_start += 4;
        if(ptr_start+size>ptr_end)
            sec = ptr_end - ptr_start;
        if(sec>31)
            sec = 31;
        memcpy(id3_artist, ptr_start, sec-1);
    }
    else
        goto ID3_ERR;
    ptr_start += size;
    if(*ptr_start == 0)
        ptr_start++;

    while (ptr_start < ptr_end) {
        if (str_memcmp(ptr_start, (void __code*)wav_comment_header[4], 4)) {  //IPRD
            flag = 1;
            break;
        }else {
            flag = 0;
        }
        ptr_start += 4;
    }
    if(!flag)
        goto ID3_ERR;
    ptr_start += 4;
    if(ptr_start+5 < ptr_end)
    {
        size = get_data32(ptr_start, 0);
        if (!size) {
            goto ID3_ERR;
        }
        ptr_start += 4;
        if(ptr_start+size>ptr_end)
            size = ptr_end - ptr_start;
        if(size>41)
            size = 41;
        memcpy(id3_album, ptr_start, size-1);
    }
ID3_ERR:
    //player_flag.f_file_eof = 0;
    //player_flag.f_eof = 0;
    f_seek_opt(0, 0);
    return ID3_OK;
}

//获取len byte数据存至buf
#pragma location="MUSIC_ID3_SEG_1"
void get_strs(u16 len, u8 *buf, u16 buf_size)
{
    unsigned char c;
    unsigned char *q;

    q = buf;
    while (len > 0) {
        c = m_player_getbyte();
        if ((q - buf) < buf_size - 1) {
            //if (c != 0) {
                *q++ = c;
            //}
        }
        len--;
    }
    *q = '\0';
}

//WMA ASF头信息的获取
#pragma optimize=no_inline
#pragma location="MUSIC_ID3_SEG_2"
u8 wma_asfhead_get_info(GUID g, u32 gsize)
{
    u8 len;//, len2, len3, len4, len5;
    u32 len_cnt;
#if 1
    if (GUID_CMP(g, ff_asf_comment_header))
    {
        len_cnt = m_player_getle16();    //title
        len = m_player_getle16();  //author
        //len3 = m_player_getle16();  //copyright
        //len4 = m_player_getle16();  //comment
        //len5 = m_player_getle16();  //album
        m_player_skipbytes(6);
        if(len_cnt)
            get_strs(len_cnt, (u8 *)id3_title, 31);
        id3_title[30] = 1;
        if(len)
            get_strs(len, (u8 *)id3_artist, 31);
        id3_artist[30] = 1;
        /*
        u8 i;
        for (i=0; i<len1; i++) {
            printf("%02x ", filename[i]);
        }*/
        m_player_skipbytes(gsize - 24 - 10 - len - len_cnt);
        //get_strs(len2, (u8 *)filename, FILE_NAME_LEN);
        //get_strs(len3, (u8 *)filename, FILE_NAME_LEN);
        //get_strs(len4, (u8 *)filename, FILE_NAME_LEN);
        //get_strs(len5, (u8 *)filename, FILE_NAME_LEN);
        return 1;
    }
    else if (GUID_CMP(g, ff_asf_exinfo_comment_header))//扩展tag
    {
        len_cnt = 26;
        u8 ext_num =  m_player_getle16();//扩展信息个数
            while((len_cnt < gsize) && ext_num)
            {
                len = m_player_getle16();//扩展信息名字大小
                len_cnt += 6;
                len_cnt += len;

                //printf("%d,h:%04x,", ext_num, len);
                if(len == 0x1c)
                {
                    get_strs(len, (u8 *)id3_buff_temp, 41);
                    m_player_skipbytes(2);//跳掉flag
                    len = m_player_getle16();//扩展信息值大小
                    len_cnt += len;
                    if(str_memcmp(id3_buff_temp,(void __code*)wma_album_title, 0x19))
                    {
                        get_strs(len, (u8 *)id3_album, 41);
                        id3_album[40] = 1;
                        break;
                    } else {
                        m_player_skipbytes(len);
                    }
                }
                else
                {
                    m_player_skipbytes(len+2);
                    len = m_player_getle16();//扩展信息值大小
                    len_cnt += len;
                    m_player_skipbytes(len);
                }

                //printf("v%04x,a:%08lx\n", len, len_cnt);
                ext_num--;
            }
        //printf("s:%08lx\n", gsize - len_cnt);
        m_player_skipbytes(gsize - len_cnt);
        return 1;
    }
#endif
    return 2;
}

//重写 maskrom wma_asfhead_hook函数
__near_func u8 wma_asfhead_hook_mod(GUID g, u32 gsize)
{
    return wma_asfhead_get_info(g, gsize);
}


//解析MP3 ID3 V1格式歌曲信息
#pragma location="MUSIC_ID3_SEG_2"
bool mp3_ID3_V1(void)
{
    u32 len, sec, surplus;
    u8 *buff_ptr = music_ID3_buff;
    u8 i;

    len = fat_file_opt.fsize + 1;
    sec = (u32)(len / fat_fs.s_size);
    surplus = len - sec * fat_fs.s_size;
    //printf("len=%ld sec=%ld\n", len, sec);
    //printf("sur=%ld\n", surplus);
    if (surplus > 128) {
        f_seek_opt(0, sec);
        f_read_opt(buff_ptr);
        for (i=0; i<128; i++) {
            buff_ptr[i] = buff_ptr[surplus-129+i];
        }
    } else {
        f_seek_opt(0, sec-1);
        f_read_opt(buff_ptr);
        f_read_opt(buff_ptr+512);
        for (i=0;i<128;i++) {
            buff_ptr[i] = buff_ptr[512+surplus-129+i];
        }
    }
    if (*buff_ptr++=='T' && *buff_ptr++=='A' && *buff_ptr++=='G') {
        memcpy(id3_title, buff_ptr, 30);
        buff_ptr+=30;
        memcpy(id3_artist, buff_ptr, 30);
        buff_ptr += 30;
        memcpy(id3_album, buff_ptr,30);
        //player_flag.f_file_eof = 0;
        //player_flag.f_eof = 0;
        f_seek_opt(0, 0);
        return true;
    }
    //player_flag.f_file_eof = 0;
    //player_flag.f_eof = 0;
    f_seek_opt(0, 0);
    return false;
}

u8 utf8_char_size(char code);
//UTF8 转换为 UTF16
#pragma location="MUSIC_ID3_SEG_1"
u8 utf8_to_utf16(u8 *utf16_ptr, u8 *utf8_ptr, u32 len)
{
    u8 ch, ch1, i, j=0;
    u8 utf8_size, t1=0, t2=0, t3=0;
    /*
    u32 k;
    for (k=0; k<len; k++) {
        printf("%02x ", utf8_ptr[k]);
    }
    printf("\n");*/
    for (i=0; i<len; ) {
        ch = utf8_ptr[i++];
        utf8_size = utf8_char_size(ch);
        switch (utf8_size) {
        case 1:
            ch1 = 0;
            break;
        case 2:
            t1 = ch & (0x1f);//高位的后5位！（去除了头部的110这个标志位）
            t2 = utf8_ptr[i++] & (0x3f);//低位的后6位！（去除了头部的10这个标志位）
            ch = t2 | ((t1 & (0x03)) << 6);
            ch1 = t1 >> 2;//留下其保留的三位
            break;
        case 3:
            t1 = ch & (0x1f);
            t2 = utf8_ptr[i++] & (0x3f);
            t3 = utf8_ptr[i++] & (0x3f);
            ch = ((t2 & (0x03)) << 6) | t3;
            ch1 = (t1 << 4) | (t2 >> 2);
            break;
        }
        if (!ch && !ch1) {    //UTF-16必须要ch和ch1都为0才为0
            break;
        } else {
            utf16_ptr[j++] = ch;
            utf16_ptr[j++] = ch1;
        }
    }
    return j;
    /*
    for (k=0; k<j; k++) {
        printf("%02x ", utf16_ptr[k]);
    }
    printf("\n");*/
}

//UTF-16BE转UTF-16
#pragma location="MUSIC_ID3_SEG_1"
void utf16be_to_utf16(u8 *utf16_ptr, u8 *utf16be_ptr, u32 len)
{
    u8 i;

    for (i=0; i<len; i++) {
        utf16_ptr[i*2+1] = utf16be_ptr[i*2];
        utf16_ptr[i*2] = utf16be_ptr[i*2+1];
    }
}


//解析MP3 ID3 V2格式歌曲信息(V2.3, V2.4)
#pragma location="MUSIC_ID3_SEG_2"
bool mp3_ID3_V2(void)
{
    //u16 frame_flag;
    u8 *ptr_start, *ptr_end;
    u32 frame_size;
    u8 unicode_flag ;
    u8 id3_flag;
    u8 info_count = 0;//记录需要的标签数目
    u16 label_len;
    u8 size_temp;
    ptr_start = music_ID3_buff;
    f_seek_opt(0, 0);
    f_read_opt(ptr_start);
    f_read_opt(ptr_start+512);    //读1024k byte data
    /*u8 i;
    for (i=0; i<10; i++) {
        printf("%02x ", ptr_start[i]);
    }*/
    if (!(ptr_start[0]=='I' && ptr_start[1]=='D' && ptr_start[2]=='3')) {
        return false;
    }
    if (ptr_start[3] == 0xff || ptr_start[4] == 0xff ||(ptr_start[6] & 0x80) || (ptr_start[7] & 0x80) || (ptr_start[8] & 0x80) || (ptr_start[9] & 0x80)) {
        return false;
    }
    msc_ID3.major_ver = ptr_start[3];  //版本号
    //printf("ver=%02x\n", msc_ID3.major_ver);
    //msc_ID3.revision = ptr_start[4];   //副版本号，一般为00
    id3_flag = ptr_start[5];       //存放标志
    msc_ID3.total_size = ((u32)ptr_start[6]<<21) | ((u32)ptr_start[7]<<14) | ((u32)ptr_start[8] <<7) | (ptr_start[9] <<0);  //标签大小，只有28bit,每byte的最高bit=0
    if ((msc_ID3.major_ver != 0x03 && msc_ID3.major_ver != 0x04) || msc_ID3.total_size == 0) {   //一般只支持V2.3
        return false;
    }
    //printf("size:%ld\n",msc_ID3.total_size);
    if (msc_ID3.total_size > 1024) {
        frame_size = 1024 - 10;
    }
    else
       frame_size = msc_ID3.total_size;
    msc_ID3.total_size -= frame_size;
    /*
    for (i=0; i<10; i++) {
        printf("%02x ", head[i]);
    }
    printf("\n");
    printf("major=%02x rev=%02x flag=%02x size=%ld\n", msc_ID3.major_ver, msc_ID3.revision, id3_flag, msc_ID3.total_size);*/
    if (id3_flag & 0x80 || id3_flag & 0x40 || id3_flag & 0x20) {   //Unsynchronisation
        return false;
    }
    ptr_start += 10;
    ptr_end = ptr_start + frame_size;
    //printf("start=%04x end=%04x\n", ptr_start, ptr_end);
    while (ptr_start <= ptr_end) {
        if ((ptr_end - ptr_start) < 10) {  //每帧都有10byte帧头信息和至少1byte的内容
            if(msc_ID3.total_size)
            {
                size_temp = ptr_end - ptr_start;
                memcpy(music_ID3_buff,ptr_start,size_temp);
                ptr_start = music_ID3_buff;
                f_read_opt(&ptr_start[size_temp]);
                if(msc_ID3.total_size>512)
                {
                    msc_ID3.total_size -= 512;
                    ptr_end = ptr_start + size_temp + 512;
                }
                else
                {
                    ptr_end = ptr_start + size_temp + msc_ID3.total_size;
                    msc_ID3.total_size = 0;
                }

            }
            else
                break;
        }
        memcpy(msc_ID3.frame_id, ptr_start, 4);
        ptr_start += 4;
        if (msc_ID3.major_ver == 0x03) {
            //V2.3
            frame_size = get_data32(ptr_start, 1);
        } else if (msc_ID3.major_ver == 0x04) {
            //V2.4
            frame_size = ((u32)ptr_start[0]<<21) | ((u32)ptr_start[1]<<14) | ((u32)ptr_start[2] <<7) | (ptr_start[3] <<0);  //每byte最高bit为0
        }
        //printf("frame_size=%08lx\n", frame_size);
        //frame_flag = int2(&ptr_start[8]);
        ptr_start += 6;
        if (msc_ID3.frame_id[0] == 0 || frame_size == 0 || (ptr_end - ptr_start) < frame_size) {
            //u8 len = ptr_end - ptr_start;
            //printf("f:%ld,r:%d\n",frame_size,len);
            if((ptr_end - ptr_start) < frame_size)
            {
                if(msc_ID3.total_size)
                {
                    size_temp = ptr_end - ptr_start;
                    memcpy(music_ID3_buff,ptr_start,size_temp);
                    ptr_start = music_ID3_buff;
                    f_read_opt(&ptr_start[size_temp]);
                    if(msc_ID3.total_size>512)
                    {
                        msc_ID3.total_size -= 512;
                        ptr_end = ptr_start + size_temp + 512;
                    }
                    else
                    {
                        ptr_end = ptr_start + size_temp + msc_ID3.total_size;
                        msc_ID3.total_size = 0;
                    }
                }
            }
            else
                break;
        }
        /*
        for (i=0; i<4; i++) {
            printf("%02x ", msc_ID3.frame_id[i]);
        }
        printf("\n");*/

        if (ptr_start[0] == 0x00) {   //ISO-8859-1
            ptr_start++;
            frame_size -= 1;
            unicode_flag = NOTUNICODE;
        } else if (ptr_start[0] == 0x01) {   //UTF-16-BOM
            if (ptr_start[1]==0xFF && ptr_start[2]==0xFE) {       //LE
                unicode_flag = UTF_16LE;
            } else if (ptr_start[1]==0xFE&&ptr_start[2]==0xFF) {  //BE
                unicode_flag = UTF_16BE;
            }
            ptr_start += 3;
            frame_size -= 3;
        } else if (ptr_start[0] == 0x02) {  //UTF-16-without BOM
            ptr_start++;
            frame_size -= 1;
            unicode_flag = UTF_16BE;
        } else if (ptr_start[0] == 0x03) {  //UTF-8
            ptr_start++;
            frame_size -= 1;
            unicode_flag = UTF_8;
        }
        for(u8 i=0;i<3;i++)
        {
            if(0 == memcmp(msc_ID3.frame_id, (char *)(ID3_TBL[i]), 4))
            {
                info_count ++;
                label_len = frame_size;
                if(label_len > 50)
                {
                    label_len = 50;
                }
                memset(id3_buff_temp, 0, sizeof(id3_buff_temp));
                if (unicode_flag == UTF_8) {
                    label_len = utf8_to_utf16((u8 *)id3_buff_temp, ptr_start, label_len);     //将UTF-8转换为UTF-16
                } else if (unicode_flag == UTF_16BE) {
                    utf16be_to_utf16((u8 *)id3_buff_temp, ptr_start, label_len);  //将UTF-16BE转换为UTF-16
                } else if (unicode_flag == UTF_16LE) {
                    memcpy(id3_buff_temp, ptr_start, label_len);
                } else {
                    memcpy(id3_buff_temp, ptr_start, label_len);
                    //ptr_buf[ID3_FLAG] |= 0x80;  //GB编码，设上此BIT
                }
                if(i==0)
                {
                    memcpy(id3_artist,id3_buff_temp,30);
                    if(unicode_flag)
                        id3_artist[30] = 1;
                }
                else if(i==1)
                {
                    memcpy(id3_album,id3_buff_temp,40);
                    if(unicode_flag)
                        id3_album[40] = 1;
                }
                else if(i==2)
                {
                    memcpy(id3_title, id3_buff_temp, 30);
                    if(unicode_flag)
                        id3_title[30] = 1;
                }
                if(info_count>=2)
                    break;
            }
        }
        ptr_start += frame_size;

    }

    if(info_count>0)
    {
        return true;
    }
    return false;
}




extern bool mp3_init(void);

#pragma location="MUSIC_ID3_SEG_1"
bool mp3_get_ID3(void)
{
    music_clear_ID3();
    if (!mp3_ID3_V2()) {
        if (!mp3_ID3_V1()) {
            mp3_init();
            msc_ctl.all_time = 0xffff;
			return false;
        }
    }
    return true;
}

#pragma location="MUSIC_ID3_SEG_1"
void music_clear_ID3(void)
{
    memset(id3_title,0,sizeof(id3_title));
    memset(id3_album,0,sizeof(id3_album));
    memset(id3_artist,0,sizeof(id3_artist));
}

//MP3 ID3信息显示
#pragma location="MUSIC_SEG"
bool mp3_id3_sel(void)
{
#if MP3_ID3_EN
    return mp3_get_ID3();
#else
    return false;
#endif
}

//WAV ID3信息显示
#pragma location="MUSIC_SEG"
bool wav_id3_sel(void)
{
#if WAV_ID3_EN
    return wav_get_info();
#else
    return false;
#endif
}

//获取歌曲ID3信息
#pragma location="MUSIC_ID3_SEG_2"
bool music_decode_ID3(void)
{
    if (t_msc.music_type == TYPE_MP3) {
        if (!mp3_id3_sel()) {
            return false;
        }
    } else if (t_msc.music_type == TYPE_WAV) {
        if (!wav_id3_sel()) {
            return false;
        }
    }
    return true;
}

#endif
