⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 id3.c

📁 在SOPC平台上
💻 C
📖 第 1 页 / 共 2 页
字号:
/***************************************************************************
 *             __________               __   ___.
 *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
 *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
 *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
 *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
 *                     \/            \/     \/    \/            \/
 *
 * Copyright (C) 2002 by Linus Nielsen Feltzing
 *
 * All files in this archive are subject to the GNU General Public License.
 * See the file COPYING in the source tree root for full license agreement.
 *
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
 * KIND, either express or implied.
 *
 ****************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdbool.h>
#include <unistd.h>
#include "id3.h"
#include "player_lib.h"

#define UNSYNC(b0,b1,b2,b3) (((long)(b0 & 0x7F) << (3*7)) | \
                             ((long)(b1 & 0x7F) << (2*7)) | \
                             ((long)(b2 & 0x7F) << (1*7)) | \
                             ((long)(b3 & 0x7F) << (0*7)))

#define BYTES2INT(b0,b1,b2,b3) (((long)(b0 & 0xFF) << (3*8)) |  \
                                ((long)(b1 & 0xFF) << (2*8)) |  \
                                ((long)(b2 & 0xFF) << (1*8)) |  \
                                ((long)(b3 & 0xFF) << (0*8)))


#ifndef MIN
#define MIN(a, b) (((a)<(b))?(a):(b))
#endif


/* parse numeric value from string */
static int parsetracknum( struct id3info* entry, char* tag, int bufferpos )
{
    entry->tracknum = atoi( tag );
    return bufferpos;
}
/* parse numeric value from string */
static int parseyearnum( struct id3info* entry, char* tag, int bufferpos )
{
    entry->year = atoi( tag );
    return bufferpos;
}

/* parse numeric genre from string, version 2.2 and 2.3 */
static int parsegenre( struct id3info* entry, char* tag, int bufferpos )
{
    if(entry->id3version >= ID3_VER_2_4) {
        /* In version 2.4 and up, there are no parentheses, and the genre frame
           is a list of strings, either numbers or text. */

        /* Is it a number? */
        if(isdigit(tag[0])) {
            entry->genre = atoi( tag );
            entry->genre_string = 0;
            return tag - entry->id3v2buf;
        } else {
            entry->genre_string = tag;
            entry->genre = 0xff;
            return bufferpos;
        }
    } else {
        if( tag[0] == '(' && tag[1] != '(' ) {
            entry->genre = atoi( tag + 1 );
            entry->genre_string = 0;
            entry->genre_string = id3_get_genre( entry );
            return tag - entry->id3v2buf;
        }
        else {
            entry->genre_string = tag;
            entry->genre = 0xff;
            return bufferpos;
        }
    }
}

/* Structure for ID3 Tag extraction information */
struct tag_resolver {
    const char* tag;
    int tag_length;
    size_t offset;
    int (*ppFunc)(struct id3info*, char* tag, int bufferpos);
};

static const struct tag_resolver taglist[] = {
    { "TPE1", 4, offsetof(struct id3info, artist), NULL },
    { "TP1",  3, offsetof(struct id3info, artist), NULL },
    { "TIT2", 4, offsetof(struct id3info, title), NULL },
    { "TT2",  3, offsetof(struct id3info, title), NULL },
    { "TALB", 4, offsetof(struct id3info, album), NULL },
    { "TAL",  3, offsetof(struct id3info, album), NULL },
    { "TRK",  3, offsetof(struct id3info, track_string), &parsetracknum },
    { "TRCK", 4, offsetof(struct id3info, track_string), &parsetracknum },
    { "TYER", 4, offsetof(struct id3info, year_string), &parseyearnum },
    { "TYE",  3, offsetof(struct id3info, year_string), &parseyearnum },
    { "TCOM", 4, offsetof(struct id3info, composer), NULL },
    { "TCON", 4, offsetof(struct id3info, genre_string), &parsegenre },
    { "TCO",  3, offsetof(struct id3info, genre_string), &parsegenre },
};

#define TAGLIST_SIZE ((int)(sizeof(taglist) / sizeof(taglist[0])))

static bool global_ff_found;

static int getid3v2len(int fd) 
{
    char buf[6];
    int offset;
  
    /* Make sure file has a ID3 tag */
    if((-1 == ide_lseek(fd, 0, SEEK_SET)) ||
       (ide_read(fd, buf, 6) != 6) ||
       (strncmp(buf, "ID3", strlen("ID3")) != 0))
        offset = 0;

    /* Now check what the ID3v2 size field says */
    else
        if(ide_read(fd, buf, 4) != 4)
            offset = 0;
        else
            offset = UNSYNC(buf[0], buf[1], buf[2], buf[3]) + 10;

    DEBUGF("ID3V2 Length: 0x%x\n", offset);
    return offset;
}

static int unsynchronize(char* tag, int len, bool *ff_found)
{
    int i;
    unsigned char c;
    unsigned char *rp, *wp;

    wp = rp = tag;
    
    rp = (unsigned char *)tag;
    for(i = 0;i < len;i++) {
        /* Read the next byte and write it back, but don't increment the
           write pointer */
        c = *rp++;
        *wp = c;
        if(*ff_found) {
            /* Increment the write pointer if it isn't an unsynch pattern */
            if(c != 0)
                wp++;
            *ff_found = false;
        } else {
            if(c == 0xff)
                *ff_found = true;
            wp++;
        }
    }
    return (long)wp - (long)tag;
}

static int unsynchronize_frame(char* tag, int len)
{
    bool ff_found = false;

    return unsynchronize(tag, len, &ff_found);
}


static int read_unsynched(int fd, void *buf, int len)
{
    int i;
    int rc;
    int remaining = len;
    char *wp;
    char *rp;

    wp = buf;
    
    while(remaining) {
        rp = wp;
        rc = read(fd, rp, remaining);
        if(rc < 0)
            return rc;

        i = unsynchronize(wp, remaining, &global_ff_found);
        remaining -= i;
        wp += i;
    }

    return len;
}

static int unicode_munge(char* string, int *len) {
   long tmp;
   bool le = false;
   int i;
   char *str = string;
   char *outstr = string;
   bool bom = false;
   int outlen;

   if(str[0] > 0x03) {
      /* Plain old string */
      return 0;
   }
   
   /* Type 0x00 is ordinary ISO 8859-1 */
   if(str[0] == 0x00) {
      int i = --(*len);

      /* We must move the string to the left */
      while (i--) {
         string[0] = string[1];
         string++;
      }

      return 0;
   }

   /* Unicode with or without BOM */
   if(str[0] == 0x01 || str[0] == 0x02) {
      (*len)--;
      str++;
      i = 0;
   
      /* Handle frames with more than one string (needed for TXXX frames).
       */
      do {
         tmp = BYTES2INT(0, 0, str[0], str[1]);
    
         /* Now check if there is a BOM (zero-width non-breaking space, 0xfeff)
            and if it is in little or big endian format */
         if(tmp == 0xfffe) { /* Little endian? */
            bom = true;
            le = true;
            str += 2;
            (*len)-=2;
         }
    
         if(tmp == 0xfeff) { /* Big endian? */
            bom = true;
            str += 2;
            (*len)-=2;
         }
    
         /* If there is no BOM (which is a specification violation),
          let's try to guess it. If one of the bytes is 0x00, it is
          probably the most significant one. */
         if(!bom) {
            if(str[1] == 0)
               le = true;
         }
      
         outlen = *len / 2;

         do {
            if(le) {
               if(str[1])
                  outstr[i++] = '.';
               else
                  outstr[i++] = str[0];
            } else {
               if(str[0])
                  outstr[i++] = '.';
               else
                  outstr[i++] = str[1];
            }
            str += 2;
         } while((str[0] || str[1]) && (i < outlen));

         str += 2;
         outstr[i++] = 0; /* Terminate the string */
      } while(i < outlen);

      *len = i - 1;

      return 0;
   }

   /* If we come here, the string was of an unsupported type */
   *len = 1;
   outstr[0] = 0;
   return -1;
}

static int skip_unsynched(int fd, int len)
{
    int rc;
    int remaining = len;
    int rlen;
    char buf[32];

    while(remaining) {
        rlen = MIN(sizeof(buf), (unsigned int)remaining);
        rc = read(fd, buf, rlen);
        if(rc < 0)
            return rc;

        remaining -= unsynchronize(buf, rlen, &global_ff_found);
    }

    return len;
}
static const char* const genres[] = {
    "Blues", "Classic Rock", "Country", "Dance", "Disco", "Funk", "Grunge",
    "Hip-Hop", "Jazz", "Metal", "New Age", "Oldies", "Other", "Pop", "R&B",
    "Rap", "Reggae", "Rock", "Techno", "Industrial", "Alternative", "Ska",
    "Death Metal", "Pranks", "Soundtrack", "Euro-Techno", "Ambient", "Trip-Hop",
    "Vocal", "Jazz+Funk", "Fusion", "Trance", "Classical", "Instrumental",
    "Acid", "House", "Game", "Sound Clip", "Gospel", "Noise", "AlternRock",
    "Bass", "Soul", "Punk", "Space", "Meditative", "Instrumental Pop",
    "Instrumental Rock", "Ethnic", "Gothic", "Darkwave", "Techno-Industrial",
    "Electronic", "Pop-Folk", "Eurodance", "Dream", "Southern Rock", "Comedy",
    "Cult", "Gangsta", "Top 40", "Christian Rap", "Pop/Funk", "Jungle",
    "Native American", "Cabaret", "New Wave", "Psychadelic", "Rave",
    "Showtunes", "Trailer", "Lo-Fi", "Tribal", "Acid Punk", "Acid Jazz",
    "Polka", "Retro", "Musical", "Rock & Roll", "Hard Rock"
};
    
char* id3_get_genre(const struct id3info* id3)
{
    if( id3->genre_string )
        return id3->genre_string ;

    if (id3->genre < sizeof(genres)/sizeof(char*))
        return (char*)genres[id3->genre];
    return NULL;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -