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

📄 tag.c

📁 一个嵌入式Linux上的mp3播放器
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * libid3tag - ID3 tag manipulation library * Copyright (C) 2000-2004 Underbit Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA * * $Id: tag.c,v 1.20 2004/02/17 02:04:10 rob Exp $ */# ifdef HAVE_CONFIG_H#  include "config.h"# endif# include "global.h"# include <string.h># include <stdlib.h># ifdef HAVE_ASSERT_H#  include <assert.h># endif# include "id3tag.h"# include "tag.h"# include "frame.h"# include "compat.h"# include "parse.h"# include "render.h"# include "latin1.h"# include "ucs4.h"# include "genre.h"# include "crc.h"# include "field.h"# include "util.h"/* * NAME:	tag->new() * DESCRIPTION:	allocate and return a new, empty tag */struct id3_tag *id3_tag_new(void){  struct id3_tag *tag;  tag = malloc(sizeof(*tag));  if (tag) {    tag->refcount      = 0;    tag->version       = ID3_TAG_VERSION;    tag->flags         = 0;    tag->extendedflags = 0;    tag->restrictions  = 0;    tag->options       = /* ID3_TAG_OPTION_UNSYNCHRONISATION | */                         ID3_TAG_OPTION_COMPRESSION | ID3_TAG_OPTION_CRC;    tag->nframes       = 0;    tag->frames        = 0;    tag->paddedsize    = 0;  }  return tag;}/* * NAME:	tag->delete() * DESCRIPTION:	destroy a tag and deallocate all associated memory */void id3_tag_delete(struct id3_tag *tag){  assert(tag);  if (tag->refcount == 0) {    id3_tag_clearframes(tag);    if (tag->frames)      free(tag->frames);    free(tag);  }}/* * NAME:	tag->addref() * DESCRIPTION:	add an external reference to a tag */void id3_tag_addref(struct id3_tag *tag){  assert(tag);  ++tag->refcount;}/* * NAME:	tag->delref() * DESCRIPTION:	remove an external reference to a tag */void id3_tag_delref(struct id3_tag *tag){  assert(tag && tag->refcount > 0);  --tag->refcount;}/* * NAME:	tag->version() * DESCRIPTION:	return the tag's original ID3 version number */unsigned int id3_tag_version(struct id3_tag const *tag){  assert(tag);  return tag->version;}/* * NAME:	tag->options() * DESCRIPTION:	get or set tag options */int id3_tag_options(struct id3_tag *tag, int mask, int values){  assert(tag);  if (mask)    tag->options = (tag->options & ~mask) | (values & mask);  return tag->options;}/* * NAME:	tag->setlength() * DESCRIPTION:	set the minimum rendered tag size */void id3_tag_setlength(struct id3_tag *tag, id3_length_t length){  assert(tag);  tag->paddedsize = length;}/* * NAME:	tag->clearframes() * DESCRIPTION:	detach and delete all frames associated with a tag */void id3_tag_clearframes(struct id3_tag *tag){  unsigned int i;  assert(tag);  for (i = 0; i < tag->nframes; ++i) {    id3_frame_delref(tag->frames[i]);    id3_frame_delete(tag->frames[i]);  }  tag->nframes = 0;}/* * NAME:	tag->attachframe() * DESCRIPTION:	attach a frame to a tag */int id3_tag_attachframe(struct id3_tag *tag, struct id3_frame *frame){  struct id3_frame **frames;  assert(tag && frame);  frames = realloc(tag->frames, (tag->nframes + 1) * sizeof(*frames));  if (frames == 0)    return -1;  tag->frames = frames;  tag->frames[tag->nframes++] = frame;  id3_frame_addref(frame);  return 0;}/* * NAME:	tag->detachframe() * DESCRIPTION:	detach (but don't delete) a frame from a tag */int id3_tag_detachframe(struct id3_tag *tag, struct id3_frame *frame){  unsigned int i;  assert(tag && frame);  for (i = 0; i < tag->nframes; ++i) {    if (tag->frames[i] == frame)      break;  }  if (i == tag->nframes)    return -1;  --tag->nframes;  while (i++ < tag->nframes)    tag->frames[i - 1] = tag->frames[i];  id3_frame_delref(frame);  return 0;}/* * NAME:	tag->findframe() * DESCRIPTION:	find in a tag the nth (0-based) frame with the given frame ID */struct id3_frame *id3_tag_findframe(struct id3_tag const *tag,				    char const *id, unsigned int index){  unsigned int len, i;  assert(tag);  if (id == 0 || *id == 0)    return (index < tag->nframes) ? tag->frames[index] : 0;  len = strlen(id);  if (len == 4) {    struct id3_compat const *compat;    compat = id3_compat_lookup(id, len);    if (compat && compat->equiv && !compat->translate) {      id  = compat->equiv;      len = strlen(id);    }  }  for (i = 0; i < tag->nframes; ++i) {    if (strncmp(tag->frames[i]->id, id, len) == 0 && index-- == 0)      return tag->frames[i];  }  return 0;}enum tagtype {  TAGTYPE_NONE = 0,  TAGTYPE_ID3V1,  TAGTYPE_ID3V2,  TAGTYPE_ID3V2_FOOTER};staticenum tagtype tagtype(id3_byte_t const *data, id3_length_t length){  if (length >= 3 &&      data[0] == 'T' && data[1] == 'A' && data[2] == 'G')    return TAGTYPE_ID3V1;  if (length >= 10 &&      ((data[0] == 'I' && data[1] == 'D' && data[2] == '3') ||       (data[0] == '3' && data[1] == 'D' && data[2] == 'I')) &&      data[3] < 0xff && data[4] < 0xff &&      data[6] < 0x80 && data[7] < 0x80 && data[8] < 0x80 && data[9] < 0x80)    return data[0] == 'I' ? TAGTYPE_ID3V2 : TAGTYPE_ID3V2_FOOTER;  return TAGTYPE_NONE;}staticvoid parse_header(id3_byte_t const **ptr,		  unsigned int *version, int *flags, id3_length_t *size){  *ptr += 3;  *version = id3_parse_uint(ptr, 2);  *flags   = id3_parse_uint(ptr, 1);  *size    = id3_parse_syncsafe(ptr, 4);}/* * NAME:	tag->query() * DESCRIPTION:	if a tag begins at the given location, return its size */signed long id3_tag_query(id3_byte_t const *data, id3_length_t length){  unsigned int version;  int flags;  id3_length_t size;  assert(data);  switch (tagtype(data, length)) {  case TAGTYPE_ID3V1:    return 128;  case TAGTYPE_ID3V2:    parse_header(&data, &version, &flags, &size);    if (flags & ID3_TAG_FLAG_FOOTERPRESENT)      size += 10;    return 10 + size;  case TAGTYPE_ID3V2_FOOTER:    parse_header(&data, &version, &flags, &size);    return -size - 10;  case TAGTYPE_NONE:    break;  }  return 0;}staticvoid trim(char *str){  char *ptr;  ptr = str + strlen(str);  while (ptr > str && ptr[-1] == ' ')    --ptr;  *ptr = 0;}staticint v1_attachstr(struct id3_tag *tag, char const *id,		 char *text, unsigned long number){  struct id3_frame *frame;  id3_ucs4_t ucs4[31];  if (text) {    trim(text);    if (*text == 0)      return 0;  }  frame = id3_frame_new(id);  if (frame == 0)    return -1;  if (id3_field_settextencoding(&frame->fields[0],				ID3_FIELD_TEXTENCODING_ISO_8859_1) == -1)    goto fail;  if (text)    id3_latin1_decode(text, ucs4);  else    id3_ucs4_putnumber(ucs4, number);  if (strcmp(id, ID3_FRAME_COMMENT) == 0) {    if (id3_field_setlanguage(&frame->fields[1], "XXX") == -1 ||	id3_field_setstring(&frame->fields[2], id3_ucs4_empty) == -1 ||	id3_field_setfullstring(&frame->fields[3], ucs4) == -1)      goto fail;  }  else {    id3_ucs4_t *ptr = ucs4;    if (id3_field_setstrings(&frame->fields[1], 1, &ptr) == -1)      goto fail;  }  if (id3_tag_attachframe(tag, frame) == -1)    goto fail;  return 0; fail:  id3_frame_delete(frame);  return -1;}staticstruct id3_tag *v1_parse(id3_byte_t const *data){  struct id3_tag *tag;  tag = id3_tag_new();  if (tag) {    char title[31], artist[31], album[31], year[5], comment[31];    unsigned int genre, track;    tag->version = 0x0100;    tag->options |=  ID3_TAG_OPTION_ID3V1;    tag->options &= ~ID3_TAG_OPTION_COMPRESSION;    tag->restrictions =      ID3_TAG_RESTRICTION_TEXTENCODING_LATIN1_UTF8 |      ID3_TAG_RESTRICTION_TEXTSIZE_30_CHARS;    title[30] = artist[30] = album[30] = year[4] = comment[30] = 0;    memcpy(title,   &data[3],  30);    memcpy(artist,  &data[33], 30);    memcpy(album,   &data[63], 30);    memcpy(year,    &data[93],  4);    memcpy(comment, &data[97], 30);    genre = data[127];    track = 0;    if (comment[28] == 0 && comment[29] != 0) {      track = comment[29];      tag->version = 0x0101;    }    /* populate tag frames */    if (v1_attachstr(tag, ID3_FRAME_TITLE,  title,  0) == -1 ||	v1_attachstr(tag, ID3_FRAME_ARTIST, artist, 0) == -1 ||	v1_attachstr(tag, ID3_FRAME_ALBUM,  album,  0) == -1 ||	v1_attachstr(tag, ID3_FRAME_YEAR,   year,   0) == -1 ||	(track        && v1_attachstr(tag, ID3_FRAME_TRACK, 0, track) == -1) ||	(genre < 0xff && v1_attachstr(tag, ID3_FRAME_GENRE, 0, genre) == -1) ||	v1_attachstr(tag, ID3_FRAME_COMMENT, comment, 0) == -1) {      id3_tag_delete(tag);      tag = 0;    }  }  return tag;}staticstruct id3_tag *v2_parse(id3_byte_t const *ptr){  struct id3_tag *tag;  id3_byte_t *mem = 0;  tag = id3_tag_new();  if (tag) {    id3_byte_t const *end;    id3_length_t size;    parse_header(&ptr, &tag->version, &tag->flags, &size);    tag->paddedsize = 10 + size;    if ((tag->flags & ID3_TAG_FLAG_UNSYNCHRONISATION) &&	ID3_TAG_VERSION_MAJOR(tag->version) < 4) {      mem = malloc(size);      if (mem == 0)	goto fail;      memcpy(mem, ptr, size);

⌨️ 快捷键说明

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