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

📄 frame.c

📁 linux下mp3编解码程序
💻 C
字号:
/* * 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: frame.c,v 1.15 2004/01/23 09:41:32 rob Exp $ */# ifdef HAVE_CONFIG_H#  include "config.h"# endif# include "global.h"# include <stdlib.h># include <string.h># ifdef HAVE_ASSERT_H#  include <assert.h># endif# include "id3tag.h"# include "frame.h"# include "frametype.h"# include "compat.h"# include "field.h"# include "render.h"# include "parse.h"# include "util.h"staticint valid_idchar(char c){  return (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9');}/* * NAME:	frame->validid() * DESCRIPTION:	return true if the parameter string is a legal frame ID */int id3_frame_validid(char const *id){  return id &&    valid_idchar(id[0]) &&    valid_idchar(id[1]) &&    valid_idchar(id[2]) &&    valid_idchar(id[3]);}/* * NAME:	frame->new() * DESCRIPTION:	allocate and return a new frame */struct id3_frame *id3_frame_new(char const *id){  struct id3_frametype const *frametype;  struct id3_frame *frame;  unsigned int i;  if (!id3_frame_validid(id))    return 0;  frametype = id3_frametype_lookup(id, 4);  if (frametype == 0) {    switch (id[0]) {    case 'T':      frametype = &id3_frametype_text;      break;    case 'W':      frametype = &id3_frametype_url;      break;    case 'X':    case 'Y':    case 'Z':      frametype = &id3_frametype_experimental;      break;    default:      frametype = &id3_frametype_unknown;      if (id3_compat_lookup(id, 4))	frametype = &id3_frametype_obsolete;      break;    }  }  frame = malloc(sizeof(*frame) + frametype->nfields * sizeof(*frame->fields));  if (frame) {    frame->id[0] = id[0];    frame->id[1] = id[1];    frame->id[2] = id[2];    frame->id[3] = id[3];    frame->id[4] = 0;    frame->description       = frametype->description;    frame->refcount          = 0;    frame->flags             = frametype->defaultflags;    frame->group_id          = 0;    frame->encryption_method = 0;    frame->encoded           = 0;    frame->encoded_length    = 0;    frame->decoded_length    = 0;    frame->nfields           = frametype->nfields;    frame->fields            = (union id3_field *) &frame[1];    for (i = 0; i < frame->nfields; ++i)      id3_field_init(&frame->fields[i], frametype->fields[i]);  }  return frame;}void id3_frame_delete(struct id3_frame *frame){  assert(frame);  if (frame->refcount == 0) {    unsigned int i;    for (i = 0; i < frame->nfields; ++i)      id3_field_finish(&frame->fields[i]);    if (frame->encoded)      free(frame->encoded);    free(frame);  }}/* * NAME:	frame->addref() * DESCRIPTION:	add an external reference to a frame */void id3_frame_addref(struct id3_frame *frame){  assert(frame);  ++frame->refcount;}/* * NAME:	frame->delref() * DESCRIPTION:	remove an external reference to a frame */void id3_frame_delref(struct id3_frame *frame){  assert(frame && frame->refcount > 0);  --frame->refcount;}/* * NAME:	frame->field() * DESCRIPTION:	return a pointer to a field in a frame */union id3_field *id3_frame_field(struct id3_frame const *frame,				 unsigned int index){  assert(frame);  return (index < frame->nfields) ? &frame->fields[index] : 0;}staticstruct id3_frame *obsolete(char const *id, id3_byte_t const *data,			   id3_length_t length){  struct id3_frame *frame;  frame = id3_frame_new(ID3_FRAME_OBSOLETE);  if (frame) {    if (id3_field_setframeid(&frame->fields[0], id) == -1 ||	id3_field_setbinarydata(&frame->fields[1], data, length) == -1)      goto fail;  }  if (0) {  fail:    if (frame) {      id3_frame_delete(frame);      frame = 0;    }  }  return frame;}staticstruct id3_frame *unparseable(char const *id, id3_byte_t const **ptr,			      id3_length_t length, int flags,			      int group_id, int encryption_method,			      id3_length_t decoded_length){  struct id3_frame *frame = 0;  id3_byte_t *mem;  mem = malloc(length ? length : 1);  if (mem == 0)    goto fail;  frame = id3_frame_new(id);  if (frame == 0)    free(mem);  else {    memcpy(mem, *ptr, length);    frame->flags             = flags;    frame->group_id          = group_id;    frame->encryption_method = encryption_method;    frame->encoded           = mem;    frame->encoded_length    = length;    frame->decoded_length    = decoded_length;  }  if (0) {  fail:    ;  }  *ptr += length;  return frame;}staticint parse_data(struct id3_frame *frame,	       id3_byte_t const *data, id3_length_t length){  enum id3_field_textencoding encoding;  id3_byte_t const *end;  unsigned int i;  encoding = ID3_FIELD_TEXTENCODING_ISO_8859_1;  end = data + length;  for (i = 0; i < frame->nfields; ++i) {    if (id3_field_parse(&frame->fields[i], &data, end - data, &encoding) == -1)      return -1;  }  return 0;}/* * NAME:	frame->parse() * DESCRIPTION:	parse raw frame data according to the specified ID3 tag version */struct id3_frame *id3_frame_parse(id3_byte_t const **ptr, id3_length_t length,				  unsigned int version){  struct id3_frame *frame = 0;  id3_byte_t const *id, *end, *data;  id3_length_t size, decoded_length = 0;  int flags = 0, group_id = 0, encryption_method = 0;  struct id3_compat const *compat = 0;  id3_byte_t *mem = 0;  char xid[4];  id  = *ptr;  end = *ptr + length;  if (ID3_TAG_VERSION_MAJOR(version) < 4) {    switch (ID3_TAG_VERSION_MAJOR(version)) {    case 2:      if (length < 6)	goto fail;      compat = id3_compat_lookup(id, 3);      *ptr += 3;      size  = id3_parse_uint(ptr, 3);      if (size > end - *ptr)	goto fail;      end = *ptr + size;      break;    case 3:      if (length < 10)	goto fail;      compat = id3_compat_lookup(id, 4);      *ptr += 4;      size  = id3_parse_uint(ptr, 4);      flags = id3_parse_uint(ptr, 2);      if (size > end - *ptr)	goto fail;      end = *ptr + size;      if (flags & (ID3_FRAME_FLAG_FORMATFLAGS & ~0x00e0)) {	frame = unparseable(id, ptr, end - *ptr, 0, 0, 0, 0);	goto done;      }      flags =	((flags >> 1) & ID3_FRAME_FLAG_STATUSFLAGS) |	((flags >> 4) & (ID3_FRAME_FLAG_COMPRESSION |			 ID3_FRAME_FLAG_ENCRYPTION)) |	((flags << 1) & ID3_FRAME_FLAG_GROUPINGIDENTITY);      if (flags & ID3_FRAME_FLAG_COMPRESSION) {	if (end - *ptr < 4)	  goto fail;	decoded_length = id3_parse_uint(ptr, 4);      }      if (flags & ID3_FRAME_FLAG_ENCRYPTION) {	if (end - *ptr < 1)	  goto fail;	encryption_method = id3_parse_uint(ptr, 1);      }      if (flags & ID3_FRAME_FLAG_GROUPINGIDENTITY) {	if (end - *ptr < 1)	  goto fail;	group_id = id3_parse_uint(ptr, 1);      }      break;    default:      goto fail;    }    /* canonicalize frame ID for ID3v2.4 */    if (compat && compat->equiv)      id = compat->equiv;    else if (ID3_TAG_VERSION_MAJOR(version) == 2) {      xid[0] = 'Y';      xid[1] = id[0];      xid[2] = id[1];      xid[3] = id[2];      id = xid;      flags |=	ID3_FRAME_FLAG_TAGALTERPRESERVATION |	ID3_FRAME_FLAG_FILEALTERPRESERVATION;    }  }  else {  /* ID3v2.4 */    if (length < 10)      goto fail;    *ptr += 4;    size  = id3_parse_syncsafe(ptr, 4);    flags = id3_parse_uint(ptr, 2);    if (size > end - *ptr)      goto fail;    end = *ptr + size;    if (flags & (ID3_FRAME_FLAG_FORMATFLAGS & ~ID3_FRAME_FLAG_KNOWNFLAGS)) {      frame = unparseable(id, ptr, end - *ptr, flags, 0, 0, 0);      goto done;    }    if (flags & ID3_FRAME_FLAG_GROUPINGIDENTITY) {      if (end - *ptr < 1)	goto fail;      group_id = id3_parse_uint(ptr, 1);    }    if ((flags & ID3_FRAME_FLAG_COMPRESSION) &&	!(flags & ID3_FRAME_FLAG_DATALENGTHINDICATOR))      goto fail;    if (flags & ID3_FRAME_FLAG_ENCRYPTION) {      if (end - *ptr < 1)	goto fail;      encryption_method = id3_parse_uint(ptr, 1);    }    if (flags & ID3_FRAME_FLAG_DATALENGTHINDICATOR) {      if (end - *ptr < 4)	goto fail;      decoded_length = id3_parse_syncsafe(ptr, 4);    }  }  data = *ptr;  *ptr = end;  /* undo frame encodings */  if ((flags & ID3_FRAME_FLAG_UNSYNCHRONISATION) && end - data > 0) {    mem = malloc(end - data);    if (mem == 0)      goto fail;    memcpy(mem, data, end - data);    end  = mem + id3_util_deunsynchronise(mem, end - data);    data = mem;  }  if (flags & ID3_FRAME_FLAG_ENCRYPTION) {    frame = unparseable(id, &data, end - data, flags,			group_id, encryption_method, decoded_length);    goto done;  }  if (flags & ID3_FRAME_FLAG_COMPRESSION) {    id3_byte_t *decomp;    decomp = id3_util_decompress(data, end - data, decoded_length);    if (decomp == 0)      goto fail;    if (mem)      free(mem);    data = mem = decomp;    end  = data + decoded_length;  }  /* check for obsolescence */  if (compat && !compat->equiv) {    frame = obsolete(id, data, end - data);    goto done;  }  /* generate the internal frame structure */  frame = id3_frame_new(id);  if (frame) {    frame->flags    = flags;    frame->group_id = group_id;    if (compat && compat->translate) {      if (compat->translate(frame, compat->id, data, end - data) == -1)	goto fail;    }    else {      if (parse_data(frame, data, end - data) == -1)	goto fail;    }  }  if (0) {  fail:    if (frame) {      id3_frame_delete(frame);      frame = 0;    }  } done:  if (mem)    free(mem);  return frame;}staticid3_length_t render_data(id3_byte_t **ptr,			 union id3_field *fields, unsigned int length){  id3_length_t size = 0;  enum id3_field_textencoding encoding;  unsigned int i;  encoding = ID3_FIELD_TEXTENCODING_ISO_8859_1;  for (i = 0; i < length; ++i)    size += id3_field_render(&fields[i], ptr, &encoding, i < length - 1);  return size;}/* * NAME:	frame->render() * DESCRIPTION:	render a single, complete frame */id3_length_t id3_frame_render(struct id3_frame const *frame,			      id3_byte_t **ptr, int options){  id3_length_t size = 0, decoded_length, datalen;  id3_byte_t *size_ptr = 0, *flags_ptr = 0, *data = 0;  int flags;  assert(frame);  if ((frame->flags & ID3_FRAME_FLAG_TAGALTERPRESERVATION) ||      ((options & ID3_TAG_OPTION_FILEALTERED) &&       (frame->flags & ID3_FRAME_FLAG_FILEALTERPRESERVATION)))    return 0;  /* a frame must be at least 1 byte big, excluding the header */  decoded_length = render_data(0, frame->fields, frame->nfields);  if (decoded_length == 0 && frame->encoded == 0)    return 0;  /* header */  size += id3_render_immediate(ptr, frame->id, 4);  if (ptr)    size_ptr = *ptr;  size += id3_render_syncsafe(ptr, 0, 4);  if (ptr)    flags_ptr = *ptr;  flags = frame->flags;  size += id3_render_int(ptr, flags, 2);  if (flags & (ID3_FRAME_FLAG_FORMATFLAGS & ~ID3_FRAME_FLAG_KNOWNFLAGS)) {    size += id3_render_binary(ptr, frame->encoded, frame->encoded_length);    if (size_ptr)      id3_render_syncsafe(&size_ptr, size - 10, 4);    return size;  }  flags &= ID3_FRAME_FLAG_KNOWNFLAGS;  flags &= ~ID3_FRAME_FLAG_UNSYNCHRONISATION;  if (options & ID3_TAG_OPTION_UNSYNCHRONISATION)    flags |= ID3_FRAME_FLAG_UNSYNCHRONISATION;  if (!(flags & ID3_FRAME_FLAG_ENCRYPTION)) {    flags &= ~ID3_FRAME_FLAG_COMPRESSION;    if (options & ID3_TAG_OPTION_COMPRESSION)      flags |= ID3_FRAME_FLAG_COMPRESSION | ID3_FRAME_FLAG_DATALENGTHINDICATOR;  }  if (flags & ID3_FRAME_FLAG_GROUPINGIDENTITY)    size += id3_render_int(ptr, frame->group_id, 1);  if (flags & ID3_FRAME_FLAG_ENCRYPTION)    size += id3_render_int(ptr, frame->encryption_method, 1);  if (flags & ID3_FRAME_FLAG_DATALENGTHINDICATOR) {    if (flags & ID3_FRAME_FLAG_ENCRYPTION)      decoded_length = frame->decoded_length;    size += id3_render_syncsafe(ptr, decoded_length, 4);  }  if (ptr)    data = *ptr;  if (flags & ID3_FRAME_FLAG_ENCRYPTION)    datalen = id3_render_binary(ptr, frame->encoded, frame->encoded_length);  else {    if (ptr == 0)      datalen = decoded_length;    else {      datalen = render_data(ptr, frame->fields, frame->nfields);      if (flags & ID3_FRAME_FLAG_COMPRESSION) {	id3_byte_t *comp;	id3_length_t complen;	comp = id3_util_compress(data, datalen, &complen);	if (comp == 0)	  flags &= ~ID3_FRAME_FLAG_COMPRESSION;	else {	  *ptr = data;	  datalen = id3_render_binary(ptr, comp, complen);	  free(comp);	}      }    }  }  /* unsynchronisation */  if (flags & ID3_FRAME_FLAG_UNSYNCHRONISATION) {    if (data == 0)      datalen *= 2;    else {      id3_length_t newlen;      newlen = id3_util_unsynchronise(data, datalen);      if (newlen == datalen)	flags &= ~ID3_FRAME_FLAG_UNSYNCHRONISATION;      else {	*ptr   += newlen - datalen;	datalen = newlen;      }    }  }  size += datalen;  /* patch size and flags */  if (size_ptr)    id3_render_syncsafe(&size_ptr, size - 10, 4);  if (flags_ptr)    id3_render_int(&flags_ptr, flags, 2);  return size;}

⌨️ 快捷键说明

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