Example #1
0
File: tag.c Project: Jsoucek/q3ce
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;
}
Example #2
0
// returns buffer len; caller frees
int ExportMP2::AddTags(AudacityProject * WXUNUSED(project), char **buffer, bool *endOfFile, const Tags *tags)
{
#ifdef USE_LIBID3TAG
   struct id3_tag *tp = id3_tag_new();

   for (const auto &pair : tags->GetRange()) {
      const auto &n = pair.first;
      const auto &v = pair.second;
      const char *name = "TXXX";

      if (n.CmpNoCase(TAG_TITLE) == 0) {
         name = ID3_FRAME_TITLE;
      }
      else if (n.CmpNoCase(TAG_ARTIST) == 0) {
         name = ID3_FRAME_ARTIST;
      }
      else if (n.CmpNoCase(TAG_ALBUM) == 0) {
         name = ID3_FRAME_ALBUM;
      }
      else if (n.CmpNoCase(TAG_YEAR) == 0) {
         // LLL:  Some apps do not like the newer frame ID (ID3_FRAME_YEAR),
         //       so we add old one as well.
         AddFrame(tp, n, v, "TYER");
         name = ID3_FRAME_YEAR;
      }
      else if (n.CmpNoCase(TAG_GENRE) == 0) {
         name = ID3_FRAME_GENRE;
      }
      else if (n.CmpNoCase(TAG_COMMENTS) == 0) {
         name = ID3_FRAME_COMMENT;
      }
      else if (n.CmpNoCase(TAG_TRACK) == 0) {
         name = ID3_FRAME_TRACK;
      }

      AddFrame(tp, n, v, name);
   }

   tp->options &= (~ID3_TAG_OPTION_COMPRESSION); // No compression

   // If this version of libid3tag supports it, use v2.3 ID3
   // tags instead of the newer, but less well supported, v2.4
   // that libid3tag uses by default.
   #ifdef ID3_TAG_HAS_TAG_OPTION_ID3V2_3
   tp->options |= ID3_TAG_OPTION_ID3V2_3;
   #endif

   *endOfFile = false;

   id3_length_t len;

   len = id3_tag_render(tp, 0);
   *buffer = (char *)malloc(len);
   len = id3_tag_render(tp, (id3_byte_t *)*buffer);

   id3_tag_delete(tp);

   return len;
#else //ifdef USE_LIBID3TAG
   return 0;
#endif
}
Example #3
0
File: tag.c Project: 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;
}
Example #4
0
static int _BarFlyTagID3Write(BarFly_t const* fly, uint8_t const* cover_art,
		size_t cover_size, BarSettings_t const* settings)
{
	int const BUFFER_SIZE = 5;
	int const TAG_PADDED_SIZE = 1024;
	char const BAR_FLY_ID3_FRAME_DISC[] = "TPOS";

	int exit_status = 0;
	int status;
	struct id3_tag* tag;
	char buffer[BUFFER_SIZE];

	assert(fly != NULL);
	assert(fly->audio_file_path != NULL);
	assert(settings != NULL);

	/*
	 * Set the minimum size for the tag.  The tag will use CRC and compression.
	 * FIXME - figure out if the padded size is really needed.
	 */
	tag = id3_tag_new();
	if (tag == NULL) {
		BarUiMsg(settings, MSG_ERR, "Failed to create new tag.\n");
		goto error;
	}
	id3_tag_setlength(tag, TAG_PADDED_SIZE);
	id3_tag_options(tag,
			ID3_TAG_OPTION_UNSYNCHRONISATION |
			ID3_TAG_OPTION_APPENDEDTAG |
			ID3_TAG_OPTION_CRC |
			ID3_TAG_OPTION_COMPRESSION, 0);

	/*
	 * Add the data to the tag.
	 */
	status = BarFlyID3AddFrame(tag, ID3_FRAME_ARTIST, fly->artist, settings); 
	if (status != 0) {
		BarUiMsg(settings, MSG_ERR, "Failed to write artist to tag.\n");
		goto error;
	}

	status = BarFlyID3AddFrame(tag, ID3_FRAME_ALBUM, fly->album, settings);
	if (status != 0) {
		BarUiMsg(settings, MSG_ERR, "Failed to write album to tag.\n");
		goto error;
	}

	status = BarFlyID3AddFrame(tag, ID3_FRAME_TITLE, fly->title, settings);
	if (status != 0) {
		BarUiMsg(settings, MSG_ERR, "Failed to write title to tag.\n");
		goto error;
	}

	if (fly->year != 0) {
		snprintf(buffer, BUFFER_SIZE, "%hu", fly->year);
		buffer[BUFFER_SIZE - 1] = '\0';
		status = BarFlyID3AddFrame(tag, ID3_FRAME_YEAR, buffer, settings);
		if (status != 0) {
			BarUiMsg(settings, MSG_ERR, "Failed to write year to tag.\n");
			goto error;
		}
	}

	if (fly->track != 0) {
		snprintf(buffer, BUFFER_SIZE, "%hu", fly->track);
		buffer[BUFFER_SIZE - 1] = '\0';
		status = BarFlyID3AddFrame(tag, ID3_FRAME_TRACK, buffer, settings);
		if (status != 0) {
			BarUiMsg(settings, MSG_ERR, "Failed to write track number to tag.\n");
			goto error;
		}
	}

	if (fly->disc != 0) {
		snprintf(buffer, BUFFER_SIZE, "%hu", fly->disc);
		buffer[BUFFER_SIZE - 1] = '\0';
		status = BarFlyID3AddFrame(tag, BAR_FLY_ID3_FRAME_DISC, buffer,
				settings);
		if (status != 0) {
			BarUiMsg(settings, MSG_ERR, "Failed to write disc number to tag.\n");
			goto error;
		}
	}

	if (cover_art != NULL) {
		status = BarFlyID3AddCover(tag, cover_art, cover_size, settings);
		if (status != 0) {
			BarUiMsg(settings, MSG_ERR, "Failed to write cover to tag.\n");
			goto error;
		}
	}

	/*
	 * Write the tag to the file.
	 */
	status = BarFlyID3WriteFile(fly->audio_file_path, tag, settings);
	if (status != 0) {
		BarUiMsg(settings, MSG_ERR, "Failed to write the tag.\n");
		goto error;
	}

	goto end;

error:
	exit_status = -1;

end:
	if (tag != NULL) {
		id3_tag_delete(tag);
	}

	return exit_status;
}
Example #5
0
static context     *
context_create(const char *filename)
{
   context            *node = (context *) malloc(sizeof(context));
   context            *ptr, *last;
   int                 last_id = INT_MAX;

   node->refcount = 1;
   {
      struct id3_file    *file;
      struct id3_tag     *tag;
      unsigned int        i;

      file = id3_file_open(filename, ID3_FILE_MODE_READONLY);
      if (!file)
        {
           fprintf(stderr, "Unable to open tagged file %s: %s\n",
                   filename, strerror(errno));
           goto fail_free;
        }
      tag = id3_file_tag(file);
      if (!tag)
        {
           fprintf(stderr, "Unable to find ID3v2 tags in file %s\n", filename);
           id3_file_close(file);
           goto fail_free;
        }
      node->tag = id3_tag_new();
      for (i = 0; i < id3_tag_get_numframes(tag); i++)
         if (!strcmp(id3_frame_id(id3_tag_get_frame(tag, i)), "APIC"))
            id3_tag_attachframe(node->tag, id3_tag_get_frame(tag, i));
      id3_file_close(file);
   }
   node->filename = strdup(filename);
   if (!id3_ctxs)
     {
        node->id = 1;
        node->next = NULL;
        id3_ctxs = node;
        return node;
     }
   ptr = id3_ctxs;
   last = NULL;
   while (UNLIKELY(ptr && (ptr->id + 1) >= last_id))
     {
        last_id = ptr->id;
        last = ptr;
        ptr = ptr->next;
     }
   /* Paranoid! this can occur only if there are INT_MAX contexts :) */
   if (UNLIKELY(!ptr))
     {
        fprintf(stderr, "Too many open ID3 contexts\n");
        goto fail_close;
     }
   node->id = ptr->id + 1;
   if (UNLIKELY(! !last))
     {
        node->next = last->next;
        last->next = node;
     }
   else
     {
        node->next = id3_ctxs;
        id3_ctxs = node;
     }
   return node;

 fail_close:
   free(node->filename);
   id3_tag_delete(node->tag);
 fail_free:
   free(node);
   return NULL;
}
Example #6
0
// returns buffer len; caller frees
int Tags::ExportID3(char **buffer, bool *endOfFile)
{
#ifdef USE_LIBID3TAG 
   struct id3_tag *tp = id3_tag_new();
   
   if (mTitle != wxT(""))
      id3_tag_attachframe(tp, MakeID3Frame(ID3_FRAME_TITLE, mTitle.mb_str()));

   if (mArtist != wxT(""))
      id3_tag_attachframe(tp, MakeID3Frame(ID3_FRAME_ARTIST, mArtist.mb_str()));

   if (mAlbum != wxT(""))
      id3_tag_attachframe(tp, MakeID3Frame(ID3_FRAME_ALBUM, mAlbum.mb_str()));

   if (mYear != wxT(""))
      id3_tag_attachframe(tp, MakeID3Frame(ID3_FRAME_YEAR, mYear.mb_str()));

   if (mComments != wxT(""))
      id3_tag_attachframe(tp, MakeID3Frame(ID3_FRAME_COMMENT, mComments.mb_str()));

   if (mTrackNum >= 0) {
      wxString trackNumStr;
      trackNumStr.Printf(wxT("%d"), mTrackNum);
      id3_tag_attachframe(tp, MakeID3Frame(ID3_FRAME_TRACK, trackNumStr.mb_str()));
   }

   if (mGenre >= 0) {
      if (mID3V2) {
         wxString genreStr = GetGenreNum(mGenre);
         id3_tag_attachframe(tp, MakeID3Frame(ID3_FRAME_GENRE, genreStr.mb_str()));
      }
      else {
         wxString genreStr;
         genreStr.Printf(wxT("%d"), mGenre);
         id3_tag_attachframe(tp, MakeID3Frame(ID3_FRAME_GENRE, genreStr.mb_str()));
      }
   }

   if (mID3V2) {
      tp->options &= (~ID3_TAG_OPTION_COMPRESSION); // No compression

      // If this version of libid3tag supports it, use v2.3 ID3
      // tags instead of the newer, but less well supported, v2.4
      // that libid3tag uses by default.
      #ifdef ID3_TAG_OPTION_ID3V2_3
      tp->options |= ID3_TAG_OPTION_ID3V2_3;
      #endif

      *endOfFile = false;
   }
   else {
      tp->options |= ID3_TAG_OPTION_ID3V1;
      *endOfFile = true;
   }

   id3_length_t len;
   
   len = id3_tag_render(tp, 0);
   *buffer = (char *)malloc(len);
   len = id3_tag_render(tp, (id3_byte_t *)*buffer);

   id3_tag_delete(tp);

   return len;
#else //ifdef USE_LIBID3TAG 
   return 0;
#endif
}