コード例 #1
0
ファイル: tag.c プロジェクト: Jsoucek/q3ce
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);

      size = id3_util_deunsynchronise(mem, size);
      ptr  = mem;
    }

    end = ptr + size;

    if (tag->flags & ID3_TAG_FLAG_EXTENDEDHEADER) {
      switch (ID3_TAG_VERSION_MAJOR(tag->version)) {
      case 2:
	goto fail;

      case 3:
	{
	  id3_byte_t const *ehptr, *ehend;
	  id3_length_t ehsize;

	  enum {
	    EH_FLAG_CRC = 0x8000  /* CRC data present */
	  };

	  if (end - ptr < 4)
	    goto fail;

	  ehsize = id3_parse_uint(&ptr, 4);

	  if (ehsize > end - ptr)
	    goto fail;

	  ehptr = ptr;
	  ehend = ptr + ehsize;

	  ptr = ehend;

	  if (ehend - ehptr >= 6) {
	    int ehflags;
	    id3_length_t padsize;

	    ehflags = id3_parse_uint(&ehptr, 2);
	    padsize = id3_parse_uint(&ehptr, 4);

	    if (padsize > end - ptr)
	      goto fail;

	    end -= padsize;

	    if (ehflags & EH_FLAG_CRC) {
	      unsigned long crc;

	      if (ehend - ehptr < 4)
		goto fail;

	      crc = id3_parse_uint(&ehptr, 4);

	      if (crc != id3_crc_compute(ptr, end - ptr))
		goto fail;

	      tag->extendedflags |= ID3_TAG_EXTENDEDFLAG_CRCDATAPRESENT;
	    }
	  }
	}
	break;

      case 4:
	{
	  id3_byte_t const *ehptr, *ehend;
	  id3_length_t ehsize;
	  unsigned int bytes;

	  if (end - ptr < 4)
	    goto fail;

	  ehptr  = ptr;
	  ehsize = id3_parse_syncsafe(&ptr, 4);

	  if (ehsize < 6 || ehsize > end - ehptr)
	    goto fail;

	  ehend = ehptr + ehsize;

	  bytes = id3_parse_uint(&ptr, 1);

	  if (bytes < 1 || bytes > ehend - ptr)
	    goto fail;

	  ehptr = ptr + bytes;

	  /* verify extended header size */
	  {
	    id3_byte_t const *flagsptr = ptr, *dataptr = ehptr;
	    unsigned int datalen;
	    int ehflags;

	    while (bytes--) {
	      for (ehflags = id3_parse_uint(&flagsptr, 1); ehflags;
		   ehflags = (ehflags << 1) & 0xff) {
		if (ehflags & 0x80) {
		  if (dataptr == ehend)
		    goto fail;
		  datalen = id3_parse_uint(&dataptr, 1);
		  if (datalen > 0x7f || datalen > ehend - dataptr)
		    goto fail;
		  dataptr += datalen;
		}
	      }
	    }
	  }

	  tag->extendedflags = id3_parse_uint(&ptr, 1);

	  ptr = ehend;

	  if (tag->extendedflags & ID3_TAG_EXTENDEDFLAG_TAGISANUPDATE) {
	    bytes  = id3_parse_uint(&ehptr, 1);
	    ehptr += bytes;
	  }

	  if (tag->extendedflags & ID3_TAG_EXTENDEDFLAG_CRCDATAPRESENT) {
	    unsigned long crc;

	    bytes = id3_parse_uint(&ehptr, 1);
	    if (bytes < 5)
	      goto fail;

	    crc = id3_parse_syncsafe(&ehptr, 5);
	    ehptr += bytes - 5;

	    if (crc != id3_crc_compute(ptr, end - ptr))
	      goto fail;
	  }

	  if (tag->extendedflags & ID3_TAG_EXTENDEDFLAG_TAGRESTRICTIONS) {
	    bytes = id3_parse_uint(&ehptr, 1);
	    if (bytes < 1)
	      goto fail;

	    tag->restrictions = id3_parse_uint(&ehptr, 1);
	    ehptr += bytes - 1;
	  }
	}
	break;
      }
    }

    /* frames */

    while (ptr < end) {
      struct id3_frame *frame;

      if (*ptr == 0)
	break;  /* padding */

      frame = id3_frame_parse(&ptr, end - ptr, tag->version);
      if (frame == 0 || id3_tag_attachframe(tag, frame) == -1)
	goto fail;
    }

    if (ID3_TAG_VERSION_MAJOR(tag->version) < 4 &&
	id3_compat_fixup(tag) == -1)
      goto fail;
  }

  if (0) {
  fail:
    id3_tag_delete(tag);
    tag = 0;
  }

  if (mem)
    free(mem);

  return tag;
}
コード例 #2
0
ファイル: tagid3.c プロジェクト: HackLinux/jz4725
/*
 * NAME:	tag->render()
 * DESCRIPTION:	render a complete ID3 tag
 */
id3_length_t id3_tag_render(struct id3_tag const *tag, id3_byte_t *buffer)
{
  id3_length_t size = 0;
  id3_byte_t **ptr,
    *header_ptr = 0, *tagsize_ptr = 0, *crc_ptr = 0, *frames_ptr = 0;
  int flags, extendedflags;
  unsigned int i;

  assert(tag);

  if (tag->options & ID3_TAG_OPTION_ID3V1)
    return v1_render(tag, buffer);

  /* a tag must contain at least one (renderable) frame */

  for (i = 0; i < tag->nframes; ++i) {
    if (id3_frame_render(tag->frames[i], 0, 0) > 0)
      break;
  }

  if (i == tag->nframes)
    return 0;

  ptr = buffer ? &buffer : 0;

  /* get flags */

  flags         = tag->flags         & ID3_TAG_FLAG_KNOWNFLAGS;
  extendedflags = tag->extendedflags & ID3_TAG_EXTENDEDFLAG_KNOWNFLAGS;

  extendedflags &= ~ID3_TAG_EXTENDEDFLAG_CRCDATAPRESENT;
  if (tag->options & ID3_TAG_OPTION_CRC)
    extendedflags |= ID3_TAG_EXTENDEDFLAG_CRCDATAPRESENT;

  extendedflags &= ~ID3_TAG_EXTENDEDFLAG_TAGRESTRICTIONS;
  if (tag->restrictions)
    extendedflags |= ID3_TAG_EXTENDEDFLAG_TAGRESTRICTIONS;

  flags &= ~ID3_TAG_FLAG_UNSYNCHRONISATION;
  if (tag->options & ID3_TAG_OPTION_UNSYNCHRONISATION)
    flags |= ID3_TAG_FLAG_UNSYNCHRONISATION;

  flags &= ~ID3_TAG_FLAG_EXTENDEDHEADER;
  if (extendedflags)
    flags |= ID3_TAG_FLAG_EXTENDEDHEADER;

  flags &= ~ID3_TAG_FLAG_FOOTERPRESENT;
  if (tag->options & ID3_TAG_OPTION_APPENDEDTAG)
    flags |= ID3_TAG_FLAG_FOOTERPRESENT;

  /* header */

  if (ptr)
    header_ptr = *ptr;

  size += id3_render_immediate(ptr, "ID3", 3);
  size += id3_render_int(ptr, ID3_TAG_VERSION, 2);
  size += id3_render_int(ptr, flags, 1);

  if (ptr)
    tagsize_ptr = *ptr;

  size += id3_render_syncsafe(ptr, 0, 4);

  /* extended header */

  if (flags & ID3_TAG_FLAG_EXTENDEDHEADER) {
    id3_length_t ehsize = 0;
    id3_byte_t *ehsize_ptr = 0;

    if (ptr)
      ehsize_ptr = *ptr;

    ehsize += id3_render_syncsafe(ptr, 0, 4);
    ehsize += id3_render_int(ptr, 1, 1);
    ehsize += id3_render_int(ptr, extendedflags, 1);

    if (extendedflags & ID3_TAG_EXTENDEDFLAG_TAGISANUPDATE)
      ehsize += id3_render_int(ptr, 0, 1);

    if (extendedflags & ID3_TAG_EXTENDEDFLAG_CRCDATAPRESENT) {
      ehsize += id3_render_int(ptr, 5, 1);

      if (ptr)
	crc_ptr = *ptr;

      ehsize += id3_render_syncsafe(ptr, 0, 5);
    }

    if (extendedflags & ID3_TAG_EXTENDEDFLAG_TAGRESTRICTIONS) {
      ehsize += id3_render_int(ptr, 1, 1);
      ehsize += id3_render_int(ptr, tag->restrictions, 1);
    }

    if (ehsize_ptr)
      id3_render_syncsafe(&ehsize_ptr, ehsize, 4);

    size += ehsize;
  }

  /* frames */

  if (ptr)
    frames_ptr = *ptr;

  for (i = 0; i < tag->nframes; ++i)
    size += id3_frame_render(tag->frames[i], ptr, tag->options);

  /* padding */

  if (!(flags & ID3_TAG_FLAG_FOOTERPRESENT)) {
    if (size < tag->paddedsize)
      size += id3_render_padding(ptr, 0, tag->paddedsize - size);
    else if (tag->options & ID3_TAG_OPTION_UNSYNCHRONISATION) {
      if (ptr == 0)
	size += 1;
      else {
	if ((*ptr)[-1] == 0xff)
	  size += id3_render_padding(ptr, 0, 1);
      }
    }
  }

  /* patch tag size and CRC */

  if (tagsize_ptr)
    id3_render_syncsafe(&tagsize_ptr, size - 10, 4);

  if (crc_ptr) {
    id3_render_syncsafe(&crc_ptr,
			id3_crc_compute(frames_ptr, *ptr - frames_ptr), 5);
  }

  /* footer */

  if (flags & ID3_TAG_FLAG_FOOTERPRESENT) {
    size += id3_render_immediate(ptr, "3DI", 3);
    size += id3_render_binary(ptr, header_ptr + 3, 7);
  }

  return size;
}