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

📄 tag.c

📁 OggPlay for Symbian 是symbian上的一个媒体播放程序的源码。它支持ogg,wav等等多媒体格式。
💻 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.1 2004/05/17 19:25:38 lcanis 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
};

static
enum 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;
}

static
void 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;
}

static
void trim(char *str)
{
  char *ptr;

  ptr = str + strlen(str);
  while (ptr > str && ptr[-1] == ' ')
    --ptr;

  *ptr = 0;
}

static
int 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;
}

static
struct 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;
}

static
struct 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 + -