mirror of
https://github.com/claunia/flac.git
synced 2025-12-16 18:54:26 +00:00
major plugin revamp based on x-fixer's code
This commit is contained in:
@@ -1,169 +1,719 @@
|
||||
/* plugin_common - Routines common to several plugins
|
||||
* Copyright (C) 2002,2003,2004 Josh Coalson
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "canonical_tag.h"
|
||||
#include "id3v2.h"
|
||||
#include "vorbiscomment.h"
|
||||
#include "FLAC/assert.h"
|
||||
#include "FLAC/metadata.h"
|
||||
|
||||
static void local__safe_free(void *object)
|
||||
{
|
||||
if(0 != object)
|
||||
free(object);
|
||||
}
|
||||
|
||||
static void local__copy_field(char **dest, const char *src, unsigned n)
|
||||
{
|
||||
if(n > 0) {
|
||||
const char *p = src + n;
|
||||
while(p > src && *(--p) == ' ')
|
||||
;
|
||||
n = p - src + 1;
|
||||
if(0 != (*dest = malloc(n+1))) {
|
||||
memcpy(*dest, src, n);
|
||||
(*dest)[n] = '\0';
|
||||
}
|
||||
}
|
||||
else
|
||||
*dest = 0;
|
||||
}
|
||||
|
||||
static FLAC__bool local__get_id3v1_tag_as_canonical(const char *filename, FLAC_Plugin__CanonicalTag *tag)
|
||||
{
|
||||
FLAC_Plugin__Id3v1_Tag id3v1_tag;
|
||||
|
||||
if(FLAC_plugin__id3v1_tag_get(filename, &id3v1_tag)) {
|
||||
FLAC_plugin__canonical_tag_convert_from_id3v1(tag, &id3v1_tag);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
FLAC_Plugin__CanonicalTag *FLAC_plugin__canonical_tag_new()
|
||||
{
|
||||
FLAC_Plugin__CanonicalTag *object = (FLAC_Plugin__CanonicalTag*)malloc(sizeof(FLAC_Plugin__CanonicalTag));
|
||||
if(0 != object)
|
||||
FLAC_plugin__canonical_tag_init(object);
|
||||
return object;
|
||||
}
|
||||
|
||||
void FLAC_plugin__canonical_tag_delete(FLAC_Plugin__CanonicalTag *object)
|
||||
{
|
||||
FLAC__ASSERT(0 != object);
|
||||
FLAC_plugin__canonical_tag_clear(object);
|
||||
free(object);
|
||||
}
|
||||
|
||||
void FLAC_plugin__canonical_tag_init(FLAC_Plugin__CanonicalTag *object)
|
||||
{
|
||||
FLAC__ASSERT(0 != object);
|
||||
object->title = 0;
|
||||
object->composer = 0;
|
||||
object->performer = 0;
|
||||
object->album = 0;
|
||||
object->year_recorded = 0;
|
||||
object->year_performed = 0;
|
||||
object->track_number = 0;
|
||||
object->tracks_in_album = 0;
|
||||
object->genre = 0;
|
||||
object->comment = 0;
|
||||
}
|
||||
|
||||
void FLAC_plugin__canonical_tag_clear(FLAC_Plugin__CanonicalTag *object)
|
||||
{
|
||||
FLAC__ASSERT(0 != object);
|
||||
local__safe_free(object->title);
|
||||
local__safe_free(object->composer);
|
||||
local__safe_free(object->performer);
|
||||
local__safe_free(object->album);
|
||||
local__safe_free(object->year_recorded);
|
||||
local__safe_free(object->year_performed);
|
||||
local__safe_free(object->track_number);
|
||||
local__safe_free(object->tracks_in_album);
|
||||
local__safe_free(object->genre);
|
||||
local__safe_free(object->comment);
|
||||
FLAC_plugin__canonical_tag_init(object);
|
||||
}
|
||||
|
||||
static void local__grab(char **dest, char **src)
|
||||
{
|
||||
if(0 == *dest) {
|
||||
*dest = *src;
|
||||
*src = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void FLAC_plugin__canonical_tag_merge(FLAC_Plugin__CanonicalTag *dest, FLAC_Plugin__CanonicalTag *src)
|
||||
{
|
||||
local__grab(&dest->title, &src->title);
|
||||
local__grab(&dest->composer, &src->composer);
|
||||
local__grab(&dest->performer, &src->performer);
|
||||
local__grab(&dest->album, &src->album);
|
||||
local__grab(&dest->year_recorded, &src->year_recorded);
|
||||
local__grab(&dest->year_performed, &src->year_performed);
|
||||
local__grab(&dest->track_number, &src->track_number);
|
||||
local__grab(&dest->tracks_in_album, &src->tracks_in_album);
|
||||
local__grab(&dest->genre, &src->genre);
|
||||
local__grab(&dest->comment, &src->comment);
|
||||
}
|
||||
|
||||
void FLAC_plugin__canonical_tag_convert_from_id3v1(FLAC_Plugin__CanonicalTag *object, const FLAC_Plugin__Id3v1_Tag *id3v1_tag)
|
||||
{
|
||||
local__copy_field(&object->title, id3v1_tag->title, 30);
|
||||
local__copy_field(&object->composer, id3v1_tag->artist, 30);
|
||||
local__copy_field(&object->performer, id3v1_tag->artist, 30);
|
||||
local__copy_field(&object->album, id3v1_tag->album, 30);
|
||||
local__copy_field(&object->year_performed, id3v1_tag->year, 4);
|
||||
|
||||
/* Check for v1.1 tags. */
|
||||
if (id3v1_tag->comment.v1_1.zero == 0) {
|
||||
if(0 != (object->track_number = malloc(4)))
|
||||
sprintf(object->track_number, "%u", (unsigned)id3v1_tag->comment.v1_1.track);
|
||||
local__copy_field(&object->comment, id3v1_tag->comment.v1_1.comment, 28);
|
||||
}
|
||||
else {
|
||||
object->track_number = strdup("0");
|
||||
local__copy_field(&object->comment, id3v1_tag->comment.v1_0.comment, 30);
|
||||
}
|
||||
|
||||
object->genre = strdup(FLAC_plugin__id3v1_tag_get_genre_as_string(id3v1_tag->genre));
|
||||
}
|
||||
|
||||
void FLAC_plugin__canonical_tag_get_combined(const char *filename, FLAC_Plugin__CanonicalTag *tag)
|
||||
{
|
||||
FLAC_Plugin__CanonicalTag id3v1_tag, id3v2_tag;
|
||||
|
||||
FLAC_plugin__vorbiscomment_get(filename, tag);
|
||||
|
||||
FLAC_plugin__canonical_tag_init(&id3v2_tag);
|
||||
(void)FLAC_plugin__id3v2_tag_get(filename, &id3v2_tag);
|
||||
|
||||
FLAC_plugin__canonical_tag_init(&id3v1_tag);
|
||||
(void)local__get_id3v1_tag_as_canonical(filename, &id3v1_tag);
|
||||
|
||||
/* merge tags, preferring, in order: vorbis comments, id3v2, id3v1 */
|
||||
FLAC_plugin__canonical_tag_merge(tag, &id3v2_tag);
|
||||
FLAC_plugin__canonical_tag_merge(tag, &id3v1_tag);
|
||||
|
||||
FLAC_plugin__canonical_tag_clear(&id3v1_tag);
|
||||
FLAC_plugin__canonical_tag_clear(&id3v2_tag);
|
||||
}
|
||||
/* plugin_common - Routines common to several plugins
|
||||
* Copyright (C) 2002,2003,2004 Josh Coalson
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "canonical_tag.h"
|
||||
#include "id3v2.h"
|
||||
#include "vorbiscomment.h"
|
||||
#include "FLAC/assert.h"
|
||||
#include "FLAC/metadata.h"
|
||||
|
||||
#if 0
|
||||
#define __USE_GNU /*@@@@@@ needed on glibc systems to get wcsdup() and wcscasecmp() */
|
||||
#endif
|
||||
#include <wchar.h>
|
||||
|
||||
/*
|
||||
* Here lies hackage to get any missing wide character string functions we
|
||||
* need. The fallback implementations here are from glibc.
|
||||
*/
|
||||
|
||||
#if !defined(_MSC_VER) && !defined(HAVE_WCSDUP)
|
||||
/* Copyright (C) 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library 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
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the GNU C Library; if not, write to the Free
|
||||
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
02111-1307 USA. */
|
||||
|
||||
#include <wchar.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
|
||||
/* Duplicate S, returning an identical malloc'd string. */
|
||||
wchar_t *
|
||||
wcsdup (s)
|
||||
const wchar_t *s;
|
||||
{
|
||||
size_t len = (__wcslen (s) + 1) * sizeof (wchar_t);
|
||||
void *new = malloc (len);
|
||||
|
||||
if (new == NULL)
|
||||
return NULL;
|
||||
|
||||
return (wchar_t *) memcpy (new, (void *) s, len);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined(_MSC_VER) && !defined(HAVE_WCSCASECMP)
|
||||
/* Copyright (C) 1991, 1992, 1995, 1996, 1997 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library 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
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the GNU C Library; if not, write to the Free
|
||||
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
02111-1307 USA. */
|
||||
|
||||
#include <wctype.h>
|
||||
#include <wchar.h>
|
||||
|
||||
#ifndef weak_alias
|
||||
# define __wcscasecmp wcscasecmp
|
||||
# define TOLOWER(Ch) towlower (Ch)
|
||||
#else
|
||||
# ifdef USE_IN_EXTENDED_LOCALE_MODEL
|
||||
# define __wcscasecmp __wcscasecmp_l
|
||||
# define TOLOWER(Ch) __towlower_l ((Ch), loc)
|
||||
# else
|
||||
# define TOLOWER(Ch) towlower (Ch)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef USE_IN_EXTENDED_LOCALE_MODEL
|
||||
# define LOCALE_PARAM , loc
|
||||
# define LOCALE_PARAM_DECL __locale_t loc;
|
||||
#else
|
||||
# define LOCALE_PARAM
|
||||
# define LOCALE_PARAM_DECL
|
||||
#endif
|
||||
|
||||
/* Compare S1 and S2, ignoring case, returning less than, equal to or
|
||||
greater than zero if S1 is lexicographically less than,
|
||||
equal to or greater than S2. */
|
||||
int
|
||||
__wcscasecmp (s1, s2 LOCALE_PARAM)
|
||||
const wchar_t *s1;
|
||||
const wchar_t *s2;
|
||||
LOCALE_PARAM_DECL
|
||||
{
|
||||
wint_t c1, c2;
|
||||
|
||||
if (s1 == s2)
|
||||
return 0;
|
||||
|
||||
do
|
||||
{
|
||||
c1 = TOLOWER (*s1++);
|
||||
c2 = TOLOWER (*s2++);
|
||||
if (c1 == L'\0')
|
||||
break;
|
||||
}
|
||||
while (c1 == c2);
|
||||
|
||||
return c1 - c2;
|
||||
}
|
||||
#ifndef __wcscasecmp
|
||||
weak_alias (__wcscasecmp, wcscasecmp)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef _MSC_VER
|
||||
/* @@@ cheesy and does base 10 only */
|
||||
wchar_t *local__itow(int value, wchar_t *string)
|
||||
{
|
||||
if (value == 0) {
|
||||
string[0] = (wchar_t)'0';
|
||||
string[1] = (wchar_t)0;
|
||||
}
|
||||
else {
|
||||
/* convert backwards, then reverse string */
|
||||
wchar_t *start = string, *s;
|
||||
if (value < 0) {
|
||||
*start++ = (wchar_t)'-';
|
||||
value = -value; /* @@@ overflow at INT_MIN */
|
||||
}
|
||||
s = start;
|
||||
while (value > 0) {
|
||||
*s++ = (wchar_t)((value % 10) + '0');
|
||||
value /= 10;
|
||||
}
|
||||
*s-- = (wchar_t)0;
|
||||
while (s > start) {
|
||||
wchar_t tmp = *s;
|
||||
*s-- = *start;
|
||||
*start++ = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
return string;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* helpers
|
||||
*/
|
||||
|
||||
/* TODO: should be moved out somewhere? @@@ */
|
||||
|
||||
wchar_t *FLAC_plugin__convert_ansi_to_wide(const char *src)
|
||||
{
|
||||
int len;
|
||||
wchar_t *dest;
|
||||
|
||||
FLAC__ASSERT(0 != src);
|
||||
|
||||
len = strlen(src) + 1;
|
||||
/* copy */
|
||||
dest = malloc(len*sizeof(wchar_t));
|
||||
if (dest) mbstowcs(dest, src, len);
|
||||
return dest;
|
||||
}
|
||||
|
||||
/* TODO: more validation? @@@ */
|
||||
static __inline int utf8len(const FLAC__byte *utf8)
|
||||
{
|
||||
FLAC__ASSERT(0 != utf8);
|
||||
if ((*utf8 & 0x80) == 0)
|
||||
return 1;
|
||||
else if ((*utf8 & 0xE0) == 0xC0)
|
||||
return 2;
|
||||
else if ((*utf8 & 0xF0) == 0xE0)
|
||||
return 3;
|
||||
else return 0;
|
||||
}
|
||||
|
||||
/* TODO: validation? @@@ */
|
||||
static __inline int utf8_to_ucs2(const FLAC__byte *utf8, wchar_t *ucs2)
|
||||
{
|
||||
int len;
|
||||
FLAC__ASSERT(utf8!=0 && *utf8!=0 && ucs2!=0);
|
||||
|
||||
if (!(len = utf8len(utf8))) return 0;
|
||||
|
||||
if (len == 1)
|
||||
*ucs2 = *utf8;
|
||||
else if (len == 2)
|
||||
*ucs2 = (*utf8 & 0x3F)<<6 | (*(utf8+1) & 0x3F);
|
||||
else if (len == 3)
|
||||
*ucs2 = (*utf8 & 0x1F)<<12 | (*(utf8+1) & 0x3F)<<6 | (*(utf8+2) & 0x3F);
|
||||
else {
|
||||
FLAC__ASSERT(len == 0);
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
wchar_t *FLAC_plugin__convert_utf8_to_ucs2(const char *src, unsigned length)
|
||||
{
|
||||
wchar_t *out, *p;
|
||||
const char *s;
|
||||
int len = 0;
|
||||
/* calculate length */
|
||||
for (s=src; length && *s; len++)
|
||||
{
|
||||
int l = utf8len(s);
|
||||
if (!l) break;
|
||||
s += l;
|
||||
length -= l;
|
||||
}
|
||||
/* allocate */
|
||||
len++;
|
||||
p = out = (wchar_t*)malloc(len * sizeof(wchar_t));
|
||||
if (!out) return NULL;
|
||||
/* convert */
|
||||
for (s=src; --len; p++)
|
||||
{
|
||||
int l = utf8_to_ucs2(s, p);
|
||||
/* l==0 is possible, because real conversion */
|
||||
/* might do more careful validation */
|
||||
if (!l) break;
|
||||
s += l;
|
||||
}
|
||||
*p = 0;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
static __inline int ucs2len(wchar_t ucs2)
|
||||
{
|
||||
if (ucs2 < 0x0080)
|
||||
return 1;
|
||||
else if (ucs2 < 0x0800)
|
||||
return 2;
|
||||
else return 3;
|
||||
}
|
||||
|
||||
static __inline int ucs2_to_utf8(wchar_t ucs2, FLAC__byte *utf8)
|
||||
{
|
||||
if (ucs2 < 0x080)
|
||||
{
|
||||
utf8[0] = (FLAC__byte)ucs2;
|
||||
return 1;
|
||||
}
|
||||
else if (ucs2 < 0x800)
|
||||
{
|
||||
utf8[0] = 0xc0 | (ucs2 >> 6);
|
||||
utf8[1] = 0x80 | (ucs2 & 0x3f);
|
||||
return 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
utf8[0] = 0xe0 | (ucs2 >> 12);
|
||||
utf8[1] = 0x80 | ((ucs2 >> 6) & 0x3f);
|
||||
utf8[2] = 0x80 | (ucs2 & 0x3f);
|
||||
return 3;
|
||||
}
|
||||
}
|
||||
|
||||
char *FLAC_plugin__convert_ucs2_to_utf8(const wchar_t *src)
|
||||
{
|
||||
const wchar_t *s;
|
||||
char *out, *p;
|
||||
int len = 0;
|
||||
FLAC__ASSERT(0 != src);
|
||||
/* calculate length */
|
||||
for (s=src; *s; s++)
|
||||
len += ucs2len(*s);
|
||||
/* allocate */
|
||||
len++;
|
||||
p = out = malloc(len);
|
||||
if (!out) return NULL;
|
||||
/* convert */
|
||||
for (s=src; *s; s++)
|
||||
{
|
||||
int l = ucs2_to_utf8(*s, p);
|
||||
p += l;
|
||||
}
|
||||
*p = 0;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
/*
|
||||
* init/clear/delete
|
||||
*/
|
||||
|
||||
FLAC_Plugin__CanonicalTag *FLAC_plugin__canonical_tag_new()
|
||||
{
|
||||
FLAC_Plugin__CanonicalTag *object = (FLAC_Plugin__CanonicalTag*)malloc(sizeof(FLAC_Plugin__CanonicalTag));
|
||||
if (object != 0)
|
||||
FLAC_plugin__canonical_tag_init(object);
|
||||
return object;
|
||||
}
|
||||
|
||||
void FLAC_plugin__canonical_tag_delete(FLAC_Plugin__CanonicalTag *object)
|
||||
{
|
||||
FLAC_plugin__canonical_tag_clear(object);
|
||||
free(object);
|
||||
}
|
||||
|
||||
void FLAC_plugin__canonical_tag_init(FLAC_Plugin__CanonicalTag *object)
|
||||
{
|
||||
object->head = object->tail = 0;
|
||||
object->count = 0;
|
||||
}
|
||||
|
||||
static void FLAC_plugin__canonical_tag_clear_entry(FLAC__tag_entry *entry)
|
||||
{
|
||||
free(entry->name);
|
||||
free(entry->value);
|
||||
free(entry);
|
||||
}
|
||||
|
||||
void FLAC_plugin__canonical_tag_clear(FLAC_Plugin__CanonicalTag *object)
|
||||
{
|
||||
FLAC__tag_entry *entry = object->head;
|
||||
|
||||
while (entry)
|
||||
{
|
||||
FLAC__tag_entry *next = entry->next;
|
||||
FLAC_plugin__canonical_tag_clear_entry(entry);
|
||||
entry = next;
|
||||
}
|
||||
|
||||
FLAC_plugin__canonical_tag_init(object);
|
||||
}
|
||||
|
||||
/*
|
||||
* internal
|
||||
*/
|
||||
|
||||
static FLAC__tag_entry *FLAC_plugin__canonical_find(const FLAC_Plugin__CanonicalTag *tag, const wchar_t *name)
|
||||
{
|
||||
FLAC__tag_entry *entry = tag->head;
|
||||
|
||||
while (entry)
|
||||
{
|
||||
#if defined _MSC_VER || defined __MINGW32__
|
||||
#define FLAC__WCSCASECMP wcsicmp
|
||||
#else
|
||||
#define FLAC__WCSCASECMP wcscasecmp
|
||||
#endif
|
||||
if (!FLAC__WCSCASECMP(name, entry->name))
|
||||
#undef FLAC__WCSCASECMP
|
||||
break;
|
||||
entry = entry->next;
|
||||
}
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
/* NOTE: does NOT copy strings. takes ownership over passed strings. */
|
||||
static void FLAC_plugin__canonical_add_tail(FLAC_Plugin__CanonicalTag *tag, wchar_t *name, wchar_t *value)
|
||||
{
|
||||
FLAC__tag_entry *entry = (FLAC__tag_entry*)malloc(sizeof(FLAC__tag_entry));
|
||||
if (!entry)
|
||||
{
|
||||
free(name);
|
||||
free(value);
|
||||
return;
|
||||
}
|
||||
/* init */
|
||||
entry->name = name;
|
||||
entry->value = value;
|
||||
/* add */
|
||||
entry->prev = tag->tail;
|
||||
if (tag->tail)
|
||||
tag->tail->next = entry;
|
||||
tag->tail = entry;
|
||||
if (!tag->head)
|
||||
tag->head = entry;
|
||||
entry->next = 0;
|
||||
tag->count++;
|
||||
}
|
||||
|
||||
static void FLAC_plugin__canonical_add_new(FLAC_Plugin__CanonicalTag *tag, const wchar_t *name, const wchar_t *value)
|
||||
{
|
||||
FLAC_plugin__canonical_add_tail(tag, wcsdup(name), wcsdup(value));
|
||||
}
|
||||
|
||||
/* NOTE: does NOT copy value, but copies name */
|
||||
static void FLAC_plugin__canonical_set_nc(FLAC_Plugin__CanonicalTag *tag, const wchar_t *name, wchar_t *value)
|
||||
{
|
||||
FLAC__tag_entry *entry = FLAC_plugin__canonical_find(tag, name);
|
||||
|
||||
if (entry)
|
||||
{
|
||||
free(entry->value);
|
||||
entry->value = value;
|
||||
}
|
||||
else FLAC_plugin__canonical_add_tail(tag, wcsdup(name), value);
|
||||
}
|
||||
|
||||
/* NOTE: does NOT copy strings. takes ownership over passed strings. (except sep!) */
|
||||
static void FLAC_plugin__canonical_add_nc(FLAC_Plugin__CanonicalTag *tag, wchar_t *name, wchar_t *value, const wchar_t *sep)
|
||||
{
|
||||
FLAC__tag_entry *entry;
|
||||
|
||||
if (sep && (entry = FLAC_plugin__canonical_find(tag, name)))
|
||||
{
|
||||
unsigned newlen = wcslen(entry->value) + wcslen(value) + wcslen(sep) + 1;
|
||||
wchar_t *newvalue = realloc(entry->value, newlen*sizeof(wchar_t));
|
||||
|
||||
if (newvalue)
|
||||
{
|
||||
entry->value = newvalue;
|
||||
wcscat(entry->value, sep);
|
||||
wcscat(entry->value, value);
|
||||
}
|
||||
|
||||
free(name);
|
||||
free(value);
|
||||
}
|
||||
else FLAC_plugin__canonical_add_tail(tag, name, value);
|
||||
}
|
||||
|
||||
/*
|
||||
* manipulation
|
||||
*/
|
||||
|
||||
void FLAC_plugin__canonical_set(FLAC_Plugin__CanonicalTag *tag, const wchar_t *name, const wchar_t *value)
|
||||
{
|
||||
FLAC_plugin__canonical_set_nc(tag, name, wcsdup(value));
|
||||
}
|
||||
|
||||
void FLAC_plugin__canonical_set_new(FLAC_Plugin__CanonicalTag *tag, const wchar_t *name, const wchar_t *value)
|
||||
{
|
||||
FLAC__tag_entry *entry = FLAC_plugin__canonical_find(tag, name);
|
||||
if (!entry) FLAC_plugin__canonical_add_new(tag, name, value);
|
||||
}
|
||||
|
||||
void FLAC_plugin__canonical_set_ansi(FLAC_Plugin__CanonicalTag *tag, const wchar_t *name, const char *value)
|
||||
{
|
||||
wchar_t *val = FLAC_plugin__convert_ansi_to_wide(value);
|
||||
if (val) FLAC_plugin__canonical_set_nc(tag, name, val);
|
||||
}
|
||||
|
||||
void FLAC_plugin__canonical_add(FLAC_Plugin__CanonicalTag *tag, const wchar_t *name, const wchar_t *value, const wchar_t *sep)
|
||||
{
|
||||
FLAC__tag_entry *entry;
|
||||
|
||||
if (sep && (entry = FLAC_plugin__canonical_find(tag, name)))
|
||||
{
|
||||
unsigned newlen = wcslen(entry->value) + wcslen(value) + wcslen(sep) + 1;
|
||||
wchar_t *newvalue = realloc(entry->value, newlen*sizeof(wchar_t));
|
||||
|
||||
if (newvalue)
|
||||
{
|
||||
entry->value = newvalue;
|
||||
wcscat(entry->value, sep);
|
||||
wcscat(entry->value, value);
|
||||
}
|
||||
}
|
||||
else FLAC_plugin__canonical_add_new(tag, name, value);
|
||||
}
|
||||
|
||||
void FLAC_plugin__canonical_add_utf8(FLAC_Plugin__CanonicalTag *tag, const char *name, const char *value, unsigned namelen, unsigned vallen, const char *sep)
|
||||
{
|
||||
wchar_t *n = FLAC_plugin__convert_utf8_to_ucs2(name, namelen);
|
||||
wchar_t *v = FLAC_plugin__convert_utf8_to_ucs2(value, vallen);
|
||||
wchar_t *s = sep ? FLAC_plugin__convert_utf8_to_ucs2(sep, -1) : 0;
|
||||
|
||||
if (n && v)
|
||||
{
|
||||
FLAC_plugin__canonical_add_nc(tag, n, v, s);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (n) free(n);
|
||||
if (v) free(v);
|
||||
}
|
||||
if (s) free(s);
|
||||
}
|
||||
|
||||
const wchar_t *FLAC_plugin__canonical_get(const FLAC_Plugin__CanonicalTag *tag, const wchar_t *name)
|
||||
{
|
||||
FLAC__tag_entry *entry = FLAC_plugin__canonical_find(tag, name);
|
||||
return entry ? entry->value : 0;
|
||||
}
|
||||
|
||||
FLAC__bool FLAC_plugin__canonical_remove(FLAC_Plugin__CanonicalTag *tag, const wchar_t *name)
|
||||
{
|
||||
FLAC__tag_entry *entry = FLAC_plugin__canonical_find(tag, name);
|
||||
|
||||
if (entry)
|
||||
{
|
||||
if (entry->prev)
|
||||
entry->prev->next = entry->next;
|
||||
else tag->head = entry->next;
|
||||
|
||||
if (entry->next)
|
||||
entry->next->prev = entry->prev;
|
||||
else tag->tail = entry->prev;
|
||||
|
||||
FLAC_plugin__canonical_tag_clear_entry(entry);
|
||||
tag->count--;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void FLAC_plugin__canonical_remove_all(FLAC_Plugin__CanonicalTag *tag, const wchar_t *name)
|
||||
{
|
||||
while (FLAC_plugin__canonical_remove(tag, name));
|
||||
}
|
||||
|
||||
char *FLAC_plugin__canonical_get_formatted(FLAC__tag_iterator it)
|
||||
{
|
||||
int len1 = wcslen(it->name);
|
||||
int len2 = wcslen(it->value);
|
||||
int len = len1 + len2 + 1;
|
||||
wchar_t *val = malloc((len+1) * sizeof(wchar_t));
|
||||
|
||||
if (val)
|
||||
{
|
||||
char *res;
|
||||
|
||||
memcpy(val, it->name, len1 * sizeof(wchar_t));
|
||||
val[len1] = '=';
|
||||
memcpy(val+len1+1, it->value, len2 * sizeof(wchar_t));
|
||||
val[len] = 0;
|
||||
|
||||
res = FLAC_plugin__convert_ucs2_to_utf8(val);
|
||||
free(val);
|
||||
return res;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* merging
|
||||
*/
|
||||
|
||||
void FLAC_plugin__canonical_tag_merge(FLAC_Plugin__CanonicalTag *dest, const FLAC_Plugin__CanonicalTag *src)
|
||||
{
|
||||
FLAC__tag_entry *entry = src->head;
|
||||
|
||||
while (entry)
|
||||
{
|
||||
FLAC_plugin__canonical_set_new(dest, entry->name, entry->value);
|
||||
entry = entry->next;
|
||||
}
|
||||
}
|
||||
|
||||
static wchar_t *local__copy_field(const char *src, unsigned n)
|
||||
{
|
||||
const char *p = src + n;
|
||||
wchar_t *dest;
|
||||
FLAC__ASSERT(n > 0);
|
||||
|
||||
while (p>src && *(--p)==' ');
|
||||
|
||||
n = p - src + 1;
|
||||
if (!n) return NULL;
|
||||
|
||||
if ((dest = malloc((n+1)*sizeof(wchar_t))) != 0)
|
||||
{
|
||||
mbstowcs(dest, src, n);
|
||||
dest[n] = 0;
|
||||
}
|
||||
return dest;
|
||||
}
|
||||
|
||||
static void local__add_id3_field(FLAC_Plugin__CanonicalTag *object, const char *value, size_t length, const wchar_t *new_name)
|
||||
{
|
||||
wchar_t *tmp;
|
||||
if (0 != value && length > 0) {
|
||||
tmp = local__copy_field(value, length);
|
||||
if (tmp)
|
||||
FLAC_plugin__canonical_add_tail(object, wcsdup(new_name), tmp);
|
||||
}
|
||||
}
|
||||
|
||||
void FLAC_plugin__canonical_tag_convert_from_id3v1(FLAC_Plugin__CanonicalTag *object, const FLAC_Plugin__Id3v1_Tag *id3v1_tag)
|
||||
{
|
||||
wchar_t *tmp;
|
||||
FLAC_plugin__canonical_tag_clear(object);
|
||||
|
||||
local__add_id3_field(object, id3v1_tag->title, 30, L"TITLE");
|
||||
local__add_id3_field(object, id3v1_tag->artist, 30, L"ARTIST");
|
||||
local__add_id3_field(object, id3v1_tag->album, 30, L"ALBUM");
|
||||
local__add_id3_field(object, id3v1_tag->year, 4, L"YEAR");
|
||||
|
||||
/* check for v1.1 tags */
|
||||
if (id3v1_tag->zero == 0)
|
||||
{
|
||||
if (id3v1_tag->track && (tmp=(wchar_t*)malloc(sizeof(id3v1_tag->track)*4*sizeof(wchar_t)))!=0)
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
_itow(id3v1_tag->track, tmp, 10);
|
||||
#else
|
||||
local__itow(id3v1_tag->track, tmp);
|
||||
#endif
|
||||
FLAC_plugin__canonical_add_tail(object, wcsdup(L"TRACKNUMBER"), tmp);
|
||||
}
|
||||
local__add_id3_field(object, id3v1_tag->comment, 28, L"DESCRIPTION");
|
||||
}
|
||||
else
|
||||
{
|
||||
local__add_id3_field(object, id3v1_tag->comment, 30, L"DESCRIPTION");
|
||||
}
|
||||
|
||||
tmp = FLAC_plugin__convert_ansi_to_wide(FLAC_plugin__id3v1_tag_get_genre_as_string(id3v1_tag->genre));
|
||||
if (tmp) FLAC_plugin__canonical_add_tail(object, wcsdup(L"GENRE"), tmp);
|
||||
}
|
||||
|
||||
void FLAC_plugin__canonical_tag_convert_from_id3v2(FLAC_Plugin__CanonicalTag *object, const FLAC_Plugin__Id3v2_Tag *id3v2_tag)
|
||||
{
|
||||
FLAC_plugin__canonical_tag_clear(object);
|
||||
|
||||
local__add_id3_field(object, id3v2_tag->title , strlen(id3v2_tag->title) , L"TITLE");
|
||||
local__add_id3_field(object, id3v2_tag->composer , strlen(id3v2_tag->composer) , L"ARTIST");
|
||||
local__add_id3_field(object, id3v2_tag->performer , strlen(id3v2_tag->performer) , L"PERFORMER");
|
||||
local__add_id3_field(object, id3v2_tag->album , strlen(id3v2_tag->album) , L"ALBUM");
|
||||
local__add_id3_field(object, id3v2_tag->year_recorded , strlen(id3v2_tag->year_recorded) , L"YEAR_RECORDED");
|
||||
local__add_id3_field(object, id3v2_tag->year_performed , strlen(id3v2_tag->year_performed) , L"YEAR_PERFORMED");
|
||||
local__add_id3_field(object, id3v2_tag->track_number , strlen(id3v2_tag->track_number) , L"TRACKNUMBER");
|
||||
local__add_id3_field(object, id3v2_tag->tracks_in_album, strlen(id3v2_tag->tracks_in_album), L"TRACKS_IN_ALBUM");
|
||||
local__add_id3_field(object, id3v2_tag->genre , strlen(id3v2_tag->genre) , L"GENRE");
|
||||
local__add_id3_field(object, id3v2_tag->comment , strlen(id3v2_tag->comment) , L"DESCRIPTION");
|
||||
}
|
||||
|
||||
static FLAC__bool local__get_id3v1_tag_as_canonical(const char *filename, FLAC_Plugin__CanonicalTag *tag)
|
||||
{
|
||||
FLAC_Plugin__Id3v1_Tag id3v1_tag;
|
||||
|
||||
if (FLAC_plugin__id3v1_tag_get(filename, &id3v1_tag))
|
||||
{
|
||||
FLAC_plugin__canonical_tag_convert_from_id3v1(tag, &id3v1_tag);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static FLAC__bool local__get_id3v2_tag_as_canonical(const char *filename, FLAC_Plugin__CanonicalTag *tag)
|
||||
{
|
||||
FLAC_Plugin__Id3v2_Tag id3v2_tag;
|
||||
|
||||
if (FLAC_plugin__id3v2_tag_get(filename, &id3v2_tag))
|
||||
{
|
||||
FLAC_plugin__canonical_tag_convert_from_id3v2(tag, &id3v2_tag);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void FLAC_plugin__canonical_tag_add_id3v1(const char *filename, FLAC_Plugin__CanonicalTag *tag)
|
||||
{
|
||||
FLAC_Plugin__CanonicalTag id3v1_tag;
|
||||
|
||||
FLAC_plugin__canonical_tag_init(&id3v1_tag);
|
||||
(void)local__get_id3v1_tag_as_canonical(filename, &id3v1_tag);
|
||||
FLAC_plugin__canonical_tag_merge(tag, &id3v1_tag);
|
||||
|
||||
FLAC_plugin__canonical_tag_clear(&id3v1_tag);
|
||||
}
|
||||
|
||||
void FLAC_plugin__canonical_tag_add_id3v2(const char *filename, FLAC_Plugin__CanonicalTag *tag)
|
||||
{
|
||||
FLAC_Plugin__CanonicalTag id3v2_tag;
|
||||
|
||||
FLAC_plugin__canonical_tag_init(&id3v2_tag);
|
||||
(void)local__get_id3v2_tag_as_canonical(filename, &id3v2_tag);
|
||||
FLAC_plugin__canonical_tag_merge(tag, &id3v2_tag);
|
||||
|
||||
FLAC_plugin__canonical_tag_clear(&id3v2_tag);
|
||||
}
|
||||
|
||||
void FLAC_plugin__canonical_tag_get_combined(const char *filename, FLAC_Plugin__CanonicalTag *tag, const char *sep)
|
||||
{
|
||||
FLAC_plugin__vorbiscomment_get(filename, tag, sep);
|
||||
FLAC_plugin__canonical_tag_add_id3v2(filename, tag);
|
||||
FLAC_plugin__canonical_tag_add_id3v1(filename, tag);
|
||||
}
|
||||
|
||||
@@ -1,55 +1,118 @@
|
||||
/* plugin_common - Routines common to several plugins
|
||||
* Copyright (C) 2002,2003,2004 Josh Coalson
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef FLAC__PLUGIN_COMMON__CANONICAL_TAG_H
|
||||
#define FLAC__PLUGIN_COMMON__CANONICAL_TAG_H
|
||||
|
||||
#include "id3v1.h"
|
||||
|
||||
typedef struct {
|
||||
char *title;
|
||||
char *composer;
|
||||
char *performer;
|
||||
char *album;
|
||||
char *year_recorded;
|
||||
char *year_performed;
|
||||
char *track_number;
|
||||
char *tracks_in_album;
|
||||
char *genre;
|
||||
char *comment;
|
||||
} FLAC_Plugin__CanonicalTag;
|
||||
|
||||
FLAC_Plugin__CanonicalTag *FLAC_plugin__canonical_tag_new();
|
||||
void FLAC_plugin__canonical_tag_delete(FLAC_Plugin__CanonicalTag *);
|
||||
void FLAC_plugin__canonical_tag_init(FLAC_Plugin__CanonicalTag *);
|
||||
void FLAC_plugin__canonical_tag_clear(FLAC_Plugin__CanonicalTag *);
|
||||
|
||||
/* For each null field in dest, move the corresponding field from src
|
||||
* WATCHOUT: note that src is not-const, because fields are 'moved' from
|
||||
* src to dest and the src field is set to null.
|
||||
*/
|
||||
void FLAC_plugin__canonical_tag_merge(FLAC_Plugin__CanonicalTag *dest, FLAC_Plugin__CanonicalTag *src);
|
||||
|
||||
void FLAC_plugin__canonical_tag_convert_from_id3v1(FLAC_Plugin__CanonicalTag *, const FLAC_Plugin__Id3v1_Tag *);
|
||||
|
||||
/* Returns a merged tag based on any Vorbis comments, id3v2 tag, and id3v1.
|
||||
* In case of overlaps the preceding precedence applies.
|
||||
*/
|
||||
void FLAC_plugin__canonical_tag_get_combined(const char *filename, FLAC_Plugin__CanonicalTag *tag);
|
||||
|
||||
#endif
|
||||
/* plugin_common - Routines common to several plugins
|
||||
* Copyright (C) 2002,2003,2004 Josh Coalson
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef FLAC__PLUGIN_COMMON__CANONICAL_TAG_H
|
||||
#define FLAC__PLUGIN_COMMON__CANONICAL_TAG_H
|
||||
|
||||
#include "id3v1.h"
|
||||
#include "id3v2.h"
|
||||
|
||||
/* TODO: splay tree? */
|
||||
typedef struct tagFLAC__tag_entry FLAC__tag_entry;
|
||||
struct tagFLAC__tag_entry
|
||||
{
|
||||
FLAC__tag_entry *next, *prev;
|
||||
/* TODO: name in ascii? */
|
||||
wchar_t *name;
|
||||
wchar_t *value;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
FLAC__tag_entry *head, *tail;
|
||||
unsigned count;
|
||||
} FLAC_Plugin__CanonicalTag;
|
||||
|
||||
|
||||
typedef FLAC__tag_entry *FLAC__tag_iterator;
|
||||
|
||||
FLAC_Plugin__CanonicalTag *FLAC_plugin__canonical_tag_new();
|
||||
void FLAC_plugin__canonical_tag_init(FLAC_Plugin__CanonicalTag *);
|
||||
void FLAC_plugin__canonical_tag_clear(FLAC_Plugin__CanonicalTag *);
|
||||
void FLAC_plugin__canonical_tag_delete(FLAC_Plugin__CanonicalTag *);
|
||||
|
||||
/* note that multiple fields with the same name are allowed.
|
||||
* set - adds field if it's not present yet, or replaces
|
||||
* existing field if it's present.
|
||||
*/
|
||||
void FLAC_plugin__canonical_set(FLAC_Plugin__CanonicalTag *tag, const wchar_t *name, const wchar_t *value);
|
||||
void FLAC_plugin__canonical_set_ansi(FLAC_Plugin__CanonicalTag *tag, const wchar_t *name, const char *value);
|
||||
/* set_new - only adds field if it's not present yet. */
|
||||
void FLAC_plugin__canonical_set_new(FLAC_Plugin__CanonicalTag *tag, const wchar_t *name, const wchar_t *value);
|
||||
/* add - adds field if it's not present yet, or merges value with existing
|
||||
* field, if it's present. (sep - separator string to use when merging;
|
||||
* if sep==NULL no merging occurs - always adds new field)
|
||||
*/
|
||||
void FLAC_plugin__canonical_add(FLAC_Plugin__CanonicalTag *tag, const wchar_t *name, const wchar_t *value, const wchar_t *sep);
|
||||
void FLAC_plugin__canonical_add_utf8(FLAC_Plugin__CanonicalTag *tag, const char *name, const char *value, unsigned namelen, unsigned vallen, const char *sep); /* 'namelen'/'vallen' may be (unsigned)(-1) if 'name'/'value' is NUL-terminated */
|
||||
|
||||
/* gets value of the first field with the given name (NULL if field not found) */
|
||||
const wchar_t *FLAC_plugin__canonical_get(const FLAC_Plugin__CanonicalTag *tag, const wchar_t *name);
|
||||
/* removes first field with the given name.
|
||||
* (returns 'true' if deleted, 'false' if not found)
|
||||
*/
|
||||
FLAC__bool FLAC_plugin__canonical_remove(FLAC_Plugin__CanonicalTag *tag, const wchar_t *name);
|
||||
/* removes all fields with the given name. */
|
||||
void FLAC_plugin__canonical_remove_all(FLAC_Plugin__CanonicalTag *tag, const wchar_t *name);
|
||||
|
||||
/* enumeration */
|
||||
static __inline unsigned FLAC_plugin__canonical_get_count(FLAC_Plugin__CanonicalTag *tag)
|
||||
{
|
||||
return tag->count;
|
||||
}
|
||||
static __inline FLAC__tag_iterator FLAC_plugin__canonical_first(FLAC_Plugin__CanonicalTag *tag)
|
||||
{
|
||||
return tag->head;
|
||||
}
|
||||
static __inline FLAC__tag_iterator FLAC_plugin__canonical_next(FLAC__tag_iterator it)
|
||||
{
|
||||
return it->next;
|
||||
}
|
||||
static __inline wchar_t *FLAC_plugin__canonical_get_name(FLAC__tag_iterator it)
|
||||
{
|
||||
return it->name;
|
||||
}
|
||||
static __inline wchar_t *FLAC_plugin__canonical_get_value(FLAC__tag_iterator it)
|
||||
{
|
||||
return it->value;
|
||||
}
|
||||
|
||||
/* returns a new string containing the current entry in UTF-8 in "NAME=VALUE" form */
|
||||
char *FLAC_plugin__canonical_get_formatted(FLAC__tag_iterator it);
|
||||
|
||||
void FLAC_plugin__canonical_tag_merge(FLAC_Plugin__CanonicalTag *dest, const FLAC_Plugin__CanonicalTag *src);
|
||||
void FLAC_plugin__canonical_tag_convert_from_id3v1(FLAC_Plugin__CanonicalTag *, const FLAC_Plugin__Id3v1_Tag *);
|
||||
void FLAC_plugin__canonical_tag_convert_from_id3v2(FLAC_Plugin__CanonicalTag *, const FLAC_Plugin__Id3v2_Tag *);
|
||||
|
||||
void FLAC_plugin__canonical_tag_add_id3v1(const char *filename, FLAC_Plugin__CanonicalTag *tag);
|
||||
void FLAC_plugin__canonical_tag_add_id3v2(const char *filename, FLAC_Plugin__CanonicalTag *tag);
|
||||
|
||||
/* Returns a merged tag based on any Vorbis comments, id3v2 tag, and id3v1.
|
||||
* In case of overlaps the preceding precedence applies.
|
||||
*
|
||||
* sep - separator to use when merging fields with same name (in VorbisComment).
|
||||
* should be in UTF-8. if sep==NULL, no merging occurs, so multiple fields
|
||||
* with the same name can exist.
|
||||
*/
|
||||
void FLAC_plugin__canonical_tag_get_combined(const char *filename, FLAC_Plugin__CanonicalTag *tag, const char *sep);
|
||||
|
||||
/* helpers */
|
||||
wchar_t *FLAC_plugin__convert_ansi_to_wide(const char *src);
|
||||
wchar_t *FLAC_plugin__convert_utf8_to_ucs2(const char *src, unsigned length); /* 'length' may be (unsigned)(-1) if 'src' is NUL-terminated */
|
||||
char *FLAC_plugin__convert_ucs2_to_utf8(const wchar_t *src);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,229 +1,214 @@
|
||||
/* plugin_common - Routines common to several plugins
|
||||
* Copyright (C) 2002,2003,2004 Josh Coalson
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "FLAC/assert.h"
|
||||
#include "id3v1.h"
|
||||
#include "locale_hack.h"
|
||||
|
||||
|
||||
/*
|
||||
* Do not sort genres!!
|
||||
* Last Update: 2000/04/30
|
||||
*/
|
||||
static const char * const FLAC_plugin__id3v1_tag_genre_table[] =
|
||||
{
|
||||
"Blues", /* 0 */
|
||||
"Classic Rock",
|
||||
"Country",
|
||||
"Dance",
|
||||
"Disco",
|
||||
"Funk", /* 5 */
|
||||
"Grunge",
|
||||
"Hip-Hop",
|
||||
"Jazz",
|
||||
"Metal",
|
||||
"New Age", /* 10 */
|
||||
"Oldies",
|
||||
"Other",
|
||||
"Pop",
|
||||
"R&B",
|
||||
"Rap", /* 15 */
|
||||
"Reggae",
|
||||
"Rock",
|
||||
"Techno",
|
||||
"Industrial",
|
||||
"Alternative", /* 20 */
|
||||
"Ska",
|
||||
"Death Metal",
|
||||
"Pranks",
|
||||
"Soundtrack",
|
||||
"Euro-Techno", /* 25 */
|
||||
"Ambient",
|
||||
"Trip-Hop",
|
||||
"Vocal",
|
||||
"Jazz+Funk",
|
||||
"Fusion", /* 30 */
|
||||
"Trance",
|
||||
"Classical",
|
||||
"Instrumental",
|
||||
"Acid",
|
||||
"House", /* 35 */
|
||||
"Game",
|
||||
"Sound Clip",
|
||||
"Gospel",
|
||||
"Noise",
|
||||
"Altern Rock", /* 40 */
|
||||
"Bass",
|
||||
"Soul",
|
||||
"Punk",
|
||||
"Space",
|
||||
"Meditative", /* 45 */
|
||||
"Instrumental Pop",
|
||||
"Instrumental Rock",
|
||||
"Ethnic",
|
||||
"Gothic",
|
||||
"Darkwave", /* 50 */
|
||||
"Techno-Industrial",
|
||||
"Electronic",
|
||||
"Pop-Folk",
|
||||
"Eurodance",
|
||||
"Dream", /* 55 */
|
||||
"Southern Rock",
|
||||
"Comedy",
|
||||
"Cult",
|
||||
"Gangsta",
|
||||
"Top 40", /* 60 */
|
||||
"Christian Rap",
|
||||
"Pop/Funk",
|
||||
"Jungle",
|
||||
"Native American",
|
||||
"Cabaret", /* 65 */
|
||||
"New Wave",
|
||||
"Psychadelic",
|
||||
"Rave",
|
||||
"Showtunes",
|
||||
"Trailer", /* 70 */
|
||||
"Lo-Fi",
|
||||
"Tribal",
|
||||
"Acid Punk",
|
||||
"Acid Jazz",
|
||||
"Polka", /* 75 */
|
||||
"Retro",
|
||||
"Musical",
|
||||
"Rock & Roll",
|
||||
"Hard Rock",
|
||||
"Folk", /* 80 */
|
||||
"Folk/Rock",
|
||||
"National Folk",
|
||||
"Fast Fusion",
|
||||
"Swing",
|
||||
"Bebob", /* 85 */
|
||||
"Latin",
|
||||
"Revival",
|
||||
"Celtic",
|
||||
"Bluegrass",
|
||||
"Avantgarde", /* 90 */
|
||||
"Gothic Rock",
|
||||
"Progressive Rock",
|
||||
"Psychedelic Rock",
|
||||
"Symphonic Rock",
|
||||
"Slow Rock", /* 95 */
|
||||
"Big Band",
|
||||
"Chorus",
|
||||
"Easy Listening",
|
||||
"Acoustic",
|
||||
"Humour", /* 100 */
|
||||
"Speech",
|
||||
"Chanson",
|
||||
"Opera",
|
||||
"Chamber Music",
|
||||
"Sonata", /* 105 */
|
||||
"Symphony",
|
||||
"Booty Bass",
|
||||
"Primus",
|
||||
"Porn Groove",
|
||||
"Satire", /* 110 */
|
||||
"Slow Jam",
|
||||
"Club",
|
||||
"Tango",
|
||||
"Samba",
|
||||
"Folklore", /* 115 */
|
||||
"Ballad",
|
||||
"Power Ballad",
|
||||
"Rhythmic Soul",
|
||||
"Freestyle",
|
||||
"Duet", /* 120 */
|
||||
"Punk Rock",
|
||||
"Drum Solo",
|
||||
"A Capella",
|
||||
"Euro-House",
|
||||
"Dance Hall", /* 125 */
|
||||
"Goa",
|
||||
"Drum & Bass",
|
||||
"Club-House",
|
||||
"Hardcore",
|
||||
"Terror", /* 130 */
|
||||
"Indie",
|
||||
"BritPop",
|
||||
"Negerpunk",
|
||||
"Polsk Punk",
|
||||
"Beat", /* 135 */
|
||||
"Christian Gangsta Rap",
|
||||
"Heavy Metal",
|
||||
"Black Metal",
|
||||
"Crossover",
|
||||
"Contemporary Christian",/* 140 */
|
||||
"Christian Rock",
|
||||
"Merengue",
|
||||
"Salsa",
|
||||
"Thrash Metal",
|
||||
"Anime", /* 145 */
|
||||
"JPop",
|
||||
"Synthpop"
|
||||
};
|
||||
|
||||
|
||||
FLAC__bool FLAC_plugin__id3v1_tag_get(const char *filename, FLAC_Plugin__Id3v1_Tag *tag)
|
||||
{
|
||||
char raw[128];
|
||||
FILE *f;
|
||||
|
||||
FLAC__ASSERT(0 != filename);
|
||||
FLAC__ASSERT(0 != tag);
|
||||
|
||||
memset(tag, 0, sizeof(FLAC_Plugin__Id3v1_Tag));
|
||||
|
||||
if(0 == (f = fopen(filename, "rb")))
|
||||
return false;
|
||||
if(-1 == fseek(f, -128, SEEK_END)) {
|
||||
fclose(f);
|
||||
return false;
|
||||
}
|
||||
if(fread(raw, 1, 128, f) < 128) {
|
||||
fclose(f);
|
||||
return false;
|
||||
}
|
||||
fclose(f);
|
||||
if(strncmp(raw, "TAG", 3))
|
||||
return false;
|
||||
else {
|
||||
memcpy(tag->tag, raw, 3);
|
||||
memcpy(tag->title, raw+3, 30);
|
||||
memcpy(tag->artist, raw+33, 30);
|
||||
memcpy(tag->album, raw+63, 30);
|
||||
memcpy(tag->year, raw+93, 4);
|
||||
memcpy(tag->comment.v1_0.comment, raw+97, 30);
|
||||
tag->genre = raw[127];
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
const char *FLAC_plugin__id3v1_tag_get_genre_as_string(unsigned char genre_code)
|
||||
{
|
||||
if (genre_code < FLAC_plugin__id3v1_tag_genre_table_max())
|
||||
return gettext(FLAC_plugin__id3v1_tag_genre_table[genre_code]);
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
unsigned FLAC_plugin__id3v1_tag_genre_table_max()
|
||||
{
|
||||
return sizeof(FLAC_plugin__id3v1_tag_genre_table) / sizeof(FLAC_plugin__id3v1_tag_genre_table[0]) - 1;
|
||||
}
|
||||
/* plugin_common - Routines common to several plugins
|
||||
* Copyright (C) 2002,2003,2004 Josh Coalson
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "FLAC/assert.h"
|
||||
#include "id3v1.h"
|
||||
#include "locale_hack.h"
|
||||
|
||||
|
||||
/*
|
||||
* Do not sort genres!!
|
||||
* Last Update: 2000/04/30
|
||||
*/
|
||||
static const char * const FLAC_plugin__id3v1_tag_genre_table[] =
|
||||
{
|
||||
"Blues", /* 0 */
|
||||
"Classic Rock",
|
||||
"Country",
|
||||
"Dance",
|
||||
"Disco",
|
||||
"Funk", /* 5 */
|
||||
"Grunge",
|
||||
"Hip-Hop",
|
||||
"Jazz",
|
||||
"Metal",
|
||||
"New Age", /* 10 */
|
||||
"Oldies",
|
||||
"Other",
|
||||
"Pop",
|
||||
"R&B",
|
||||
"Rap", /* 15 */
|
||||
"Reggae",
|
||||
"Rock",
|
||||
"Techno",
|
||||
"Industrial",
|
||||
"Alternative", /* 20 */
|
||||
"Ska",
|
||||
"Death Metal",
|
||||
"Pranks",
|
||||
"Soundtrack",
|
||||
"Euro-Techno", /* 25 */
|
||||
"Ambient",
|
||||
"Trip-Hop",
|
||||
"Vocal",
|
||||
"Jazz+Funk",
|
||||
"Fusion", /* 30 */
|
||||
"Trance",
|
||||
"Classical",
|
||||
"Instrumental",
|
||||
"Acid",
|
||||
"House", /* 35 */
|
||||
"Game",
|
||||
"Sound Clip",
|
||||
"Gospel",
|
||||
"Noise",
|
||||
"Altern Rock", /* 40 */
|
||||
"Bass",
|
||||
"Soul",
|
||||
"Punk",
|
||||
"Space",
|
||||
"Meditative", /* 45 */
|
||||
"Instrumental Pop",
|
||||
"Instrumental Rock",
|
||||
"Ethnic",
|
||||
"Gothic",
|
||||
"Darkwave", /* 50 */
|
||||
"Techno-Industrial",
|
||||
"Electronic",
|
||||
"Pop-Folk",
|
||||
"Eurodance",
|
||||
"Dream", /* 55 */
|
||||
"Southern Rock",
|
||||
"Comedy",
|
||||
"Cult",
|
||||
"Gangsta",
|
||||
"Top 40", /* 60 */
|
||||
"Christian Rap",
|
||||
"Pop/Funk",
|
||||
"Jungle",
|
||||
"Native American",
|
||||
"Cabaret", /* 65 */
|
||||
"New Wave",
|
||||
"Psychadelic",
|
||||
"Rave",
|
||||
"Showtunes",
|
||||
"Trailer", /* 70 */
|
||||
"Lo-Fi",
|
||||
"Tribal",
|
||||
"Acid Punk",
|
||||
"Acid Jazz",
|
||||
"Polka", /* 75 */
|
||||
"Retro",
|
||||
"Musical",
|
||||
"Rock & Roll",
|
||||
"Hard Rock",
|
||||
"Folk", /* 80 */
|
||||
"Folk/Rock",
|
||||
"National Folk",
|
||||
"Fast Fusion",
|
||||
"Swing",
|
||||
"Bebob", /* 85 */
|
||||
"Latin",
|
||||
"Revival",
|
||||
"Celtic",
|
||||
"Bluegrass",
|
||||
"Avantgarde", /* 90 */
|
||||
"Gothic Rock",
|
||||
"Progressive Rock",
|
||||
"Psychedelic Rock",
|
||||
"Symphonic Rock",
|
||||
"Slow Rock", /* 95 */
|
||||
"Big Band",
|
||||
"Chorus",
|
||||
"Easy Listening",
|
||||
"Acoustic",
|
||||
"Humour", /* 100 */
|
||||
"Speech",
|
||||
"Chanson",
|
||||
"Opera",
|
||||
"Chamber Music",
|
||||
"Sonata", /* 105 */
|
||||
"Symphony",
|
||||
"Booty Bass",
|
||||
"Primus",
|
||||
"Porn Groove",
|
||||
"Satire", /* 110 */
|
||||
"Slow Jam",
|
||||
"Club",
|
||||
"Tango",
|
||||
"Samba",
|
||||
"Folklore", /* 115 */
|
||||
"Ballad",
|
||||
"Power Ballad",
|
||||
"Rhythmic Soul",
|
||||
"Freestyle",
|
||||
"Duet", /* 120 */
|
||||
"Punk Rock",
|
||||
"Drum Solo",
|
||||
"A Capella",
|
||||
"Euro-House",
|
||||
"Dance Hall", /* 125 */
|
||||
"Goa",
|
||||
"Drum & Bass",
|
||||
"Club-House",
|
||||
"Hardcore",
|
||||
"Terror", /* 130 */
|
||||
"Indie",
|
||||
"BritPop",
|
||||
"Negerpunk",
|
||||
"Polsk Punk",
|
||||
"Beat", /* 135 */
|
||||
"Christian Gangsta Rap",
|
||||
"Heavy Metal",
|
||||
"Black Metal",
|
||||
"Crossover",
|
||||
"Contemporary Christian",/* 140 */
|
||||
"Christian Rock",
|
||||
"Merengue",
|
||||
"Salsa",
|
||||
"Thrash Metal",
|
||||
"Anime", /* 145 */
|
||||
"JPop",
|
||||
"Synthpop"
|
||||
};
|
||||
|
||||
|
||||
FLAC__bool FLAC_plugin__id3v1_tag_get(const char *filename, FLAC_Plugin__Id3v1_Tag *tag)
|
||||
{
|
||||
FILE *f;
|
||||
int res;
|
||||
|
||||
FLAC__ASSERT(0 != filename);
|
||||
FLAC__ASSERT(0 != tag);
|
||||
|
||||
memset(tag, 0, sizeof(FLAC_Plugin__Id3v1_Tag));
|
||||
|
||||
if(0 == (f = fopen(filename, "rb")))
|
||||
return false;
|
||||
if(-1 == fseek(f, -128, SEEK_END)) {
|
||||
fclose(f);
|
||||
return false;
|
||||
}
|
||||
res = fread(tag, 128, 1, f);
|
||||
fclose(f);
|
||||
return res==1 && !strncmp(tag->tag, "TAG", 3);
|
||||
}
|
||||
|
||||
const char *FLAC_plugin__id3v1_tag_get_genre_as_string(unsigned char genre_code)
|
||||
{
|
||||
if (genre_code < (sizeof(FLAC_plugin__id3v1_tag_genre_table)/sizeof(FLAC_plugin__id3v1_tag_genre_table[0])))
|
||||
return gettext(FLAC_plugin__id3v1_tag_genre_table[genre_code]);
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
unsigned FLAC_plugin__id3v1_tag_genre_table_max()
|
||||
{
|
||||
return sizeof(FLAC_plugin__id3v1_tag_genre_table) / sizeof(FLAC_plugin__id3v1_tag_genre_table[0]) - 1;
|
||||
}
|
||||
|
||||
@@ -23,25 +23,23 @@
|
||||
|
||||
#include "FLAC/ordinals.h"
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
typedef struct {
|
||||
char tag[3];
|
||||
char title[30];
|
||||
char artist[30];
|
||||
char album[30];
|
||||
char year[4];
|
||||
union {
|
||||
struct {
|
||||
char comment[30];
|
||||
} v1_0;
|
||||
struct {
|
||||
char comment[28];
|
||||
char zero;
|
||||
unsigned char track;
|
||||
} v1_1;
|
||||
} comment;
|
||||
/* always use layout of id3 v1.1 */
|
||||
char comment[28];
|
||||
char zero;
|
||||
unsigned char track;
|
||||
unsigned char genre;
|
||||
} FLAC_Plugin__Id3v1_Tag;
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
FLAC__bool FLAC_plugin__id3v1_tag_get(const char *filename, FLAC_Plugin__Id3v1_Tag *tag);
|
||||
|
||||
|
||||
|
||||
@@ -24,6 +24,11 @@
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include "FLAC/assert.h"
|
||||
|
||||
#include <stdlib.h> /* for free() */
|
||||
#include <string.h> /* for memset() */
|
||||
|
||||
#ifdef FLAC__HAS_ID3LIB
|
||||
#include <id3.h>
|
||||
#include <stdio.h>
|
||||
@@ -32,8 +37,6 @@
|
||||
#include <ctype.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "FLAC/assert.h"
|
||||
|
||||
#include "id3v1.h" /* for genre stuff */
|
||||
#include "locale_hack.h"
|
||||
|
||||
@@ -113,25 +116,25 @@ static size_t local__ID3Field_GetASCII_wrapper(const ID3Field *field, char *buff
|
||||
* = 3.7.13 : first item num is 0 for ID3Field_GetASCII
|
||||
* >= 3.8.0 : doesn't need item num for ID3Field_GetASCII
|
||||
*/
|
||||
# if (ID3LIB_MAJOR >= 3)
|
||||
# if (ID3LIB_MAJOR >= 3)
|
||||
/* (>= 3.x.x) */
|
||||
# if (ID3LIB_MINOR <= 7)
|
||||
# if (ID3LIB_MINOR <= 7)
|
||||
/* (3.0.0 to 3.7.x) */
|
||||
# if (ID3LIB_PATCH >= 13)
|
||||
# if (ID3LIB_PATCH >= 13)
|
||||
/* (>= 3.7.13) */
|
||||
return ID3Field_GetASCII(field, buffer, maxChars, itemNum);
|
||||
# else
|
||||
# else
|
||||
return ID3Field_GetASCII(field, buffer, maxChars, itemNum+1);
|
||||
# endif
|
||||
# else
|
||||
# endif
|
||||
# else
|
||||
/* (>= to 3.8.0) */
|
||||
/*return ID3Field_GetASCII(field, buffer, maxChars); */
|
||||
return ID3Field_GetASCIIItem(field, buffer, maxChars, itemNum);
|
||||
# endif
|
||||
# else
|
||||
# endif
|
||||
# else
|
||||
/* Not tested (< 3.x.x) */
|
||||
return ID3Field_GetASCII(field, buffer, maxChars, itemNum+1);
|
||||
# endif
|
||||
# endif
|
||||
}
|
||||
|
||||
|
||||
@@ -161,7 +164,7 @@ static const char *local__genre_to_string(unsigned genre_code)
|
||||
* Returns true on success, else false.
|
||||
* If a tag entry exists (ex: title), we allocate memory, else value stays to NULL
|
||||
*/
|
||||
static FLAC__bool local__get_tag(const char *filename, FLAC_Plugin__CanonicalTag *tag)
|
||||
static FLAC__bool local__get_tag(const char *filename, FLAC_Plugin__Id3v2_Tag *tag)
|
||||
{
|
||||
FILE *file;
|
||||
ID3Tag *id3_tag = 0; /* Tag defined by id3lib */
|
||||
@@ -368,8 +371,22 @@ static FLAC__bool local__get_tag(const char *filename, FLAC_Plugin__CanonicalTag
|
||||
}
|
||||
#endif /* ifdef FLAC__HAS_ID3LIB */
|
||||
|
||||
FLAC__bool FLAC_plugin__id3v2_tag_get(const char *filename, FLAC_Plugin__CanonicalTag *tag)
|
||||
FLAC__bool FLAC_plugin__id3v2_tag_get(const char *filename, FLAC_Plugin__Id3v2_Tag *tag)
|
||||
{
|
||||
FLAC__ASSERT(0 != tag);
|
||||
if(
|
||||
0 != tag->title ||
|
||||
0 != tag->composer ||
|
||||
0 != tag->performer ||
|
||||
0 != tag->album ||
|
||||
0 != tag->year_recorded ||
|
||||
0 != tag->year_performed ||
|
||||
0 != tag->track_number ||
|
||||
0 != tag->tracks_in_album ||
|
||||
0 != tag->genre ||
|
||||
0 != tag->comment
|
||||
)
|
||||
return false;
|
||||
#ifdef FLAC__HAS_ID3LIB
|
||||
return local__get_tag(filename, tag);
|
||||
#else
|
||||
@@ -377,3 +394,29 @@ FLAC__bool FLAC_plugin__id3v2_tag_get(const char *filename, FLAC_Plugin__Canonic
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
void FLAC_plugin__id3v2_tag_clear(FLAC_Plugin__Id3v2_Tag *tag)
|
||||
{
|
||||
FLAC__ASSERT(0 != tag);
|
||||
if(0 != tag->title)
|
||||
free(tag->title);
|
||||
if(0 != tag->composer)
|
||||
free(tag->composer);
|
||||
if(0 != tag->performer)
|
||||
free(tag->performer);
|
||||
if(0 != tag->album)
|
||||
free(tag->album);
|
||||
if(0 != tag->year_recorded)
|
||||
free(tag->year_recorded);
|
||||
if(0 != tag->year_performed)
|
||||
free(tag->year_performed);
|
||||
if(0 != tag->track_number)
|
||||
free(tag->track_number);
|
||||
if(0 != tag->tracks_in_album)
|
||||
free(tag->tracks_in_album);
|
||||
if(0 != tag->genre)
|
||||
free(tag->genre);
|
||||
if(0 != tag->comment)
|
||||
free(tag->comment);
|
||||
memset(tag, 0, sizeof(*tag));
|
||||
}
|
||||
|
||||
@@ -19,8 +19,39 @@
|
||||
#ifndef FLAC__PLUGIN_COMMON__ID3V2_H
|
||||
#define FLAC__PLUGIN_COMMON__ID3V2_H
|
||||
|
||||
#include "canonical_tag.h"
|
||||
#include "FLAC/ordinals.h"
|
||||
|
||||
FLAC__bool FLAC_plugin__id3v2_tag_get(const char *filename, FLAC_Plugin__CanonicalTag *tag);
|
||||
/*
|
||||
* This is a simple structure that holds pointers to field values (in ASCII)
|
||||
* for fields we care about.
|
||||
*/
|
||||
typedef struct {
|
||||
char *title;
|
||||
char *composer;
|
||||
char *performer;
|
||||
char *album;
|
||||
char *year_recorded;
|
||||
char *year_performed;
|
||||
char *track_number;
|
||||
char *tracks_in_album;
|
||||
char *genre;
|
||||
char *comment;
|
||||
} FLAC_Plugin__Id3v2_Tag;
|
||||
|
||||
/* Fills up an existing FLAC_Plugin__Id3v2_Tag. All pointers must be NULL on
|
||||
* entry or the function will return false. For any field for which there is
|
||||
* no corresponding ID3 frame, it's pointer will be NULL.
|
||||
*
|
||||
* If loading fails, all pointers will be cleared and the function will return
|
||||
* false.
|
||||
*
|
||||
* If the function returns true, be sure to call FLAC_plugin__id3v2_tag_clear()
|
||||
* when you are done with 'tag'.
|
||||
*/
|
||||
FLAC__bool FLAC_plugin__id3v2_tag_get(const char *filename, FLAC_Plugin__Id3v2_Tag *tag);
|
||||
|
||||
/* free()s any non-NULL pointers in 'tag'. Does NOT free(tag).
|
||||
*/
|
||||
void FLAC_plugin__id3v2_tag_clear(FLAC_Plugin__Id3v2_Tag *tag);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -41,7 +41,7 @@ RSC=rc.exe
|
||||
# PROP Intermediate_Dir "Release_static"
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c
|
||||
# ADD CPP /nologo /MD /W3 /GX /Ox /Og /Oi /Os /Op /I ".\include" /I "..\..\include" /D "FLAC__NO_DLL" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c
|
||||
# ADD CPP /nologo /MD /W3 /WX /GX /Ox /Og /Oi /Os /Op /I ".\include" /I "..\..\include" /D "FLAC__NO_DLL" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c
|
||||
# ADD BASE RSC /l 0x409 /d "NDEBUG"
|
||||
# ADD RSC /l 0x409 /d "NDEBUG"
|
||||
BSC32=bscmake.exe
|
||||
|
||||
@@ -1,180 +1,110 @@
|
||||
/* plugin_common - Routines common to several plugins
|
||||
* Copyright (C) 2002,2003,2004 Josh Coalson
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "vorbiscomment.h"
|
||||
#include "FLAC/metadata.h"
|
||||
|
||||
static int local__vcentry_matches(const char *field_name, const FLAC__StreamMetadata_VorbisComment_Entry *entry)
|
||||
{
|
||||
#if defined _MSC_VER || defined __MINGW32__
|
||||
#define FLAC__STRNCASECMP strnicmp
|
||||
#else
|
||||
#define FLAC__STRNCASECMP strncasecmp
|
||||
#endif
|
||||
const FLAC__byte *eq = memchr(entry->entry, '=', entry->length);
|
||||
const unsigned field_name_length = strlen(field_name);
|
||||
return (0 != eq && (unsigned)(eq-entry->entry) == field_name_length && 0 == FLAC__STRNCASECMP(field_name, (const char *)entry->entry, field_name_length));
|
||||
}
|
||||
|
||||
static void local__vcentry_parse_value(const FLAC__StreamMetadata_VorbisComment_Entry *entry, char **dest)
|
||||
{
|
||||
const FLAC__byte *eq = memchr(entry->entry, '=', entry->length);
|
||||
|
||||
if(0 == eq)
|
||||
return;
|
||||
else {
|
||||
const unsigned value_length = entry->length - (unsigned)((++eq) - entry->entry);
|
||||
|
||||
*dest = malloc(value_length + 1);
|
||||
if(0 != *dest) {
|
||||
memcpy(*dest, eq, value_length);
|
||||
(*dest)[value_length] = '\0';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void local__vc_change_field(FLAC__StreamMetadata *block, const char *name, const char *value)
|
||||
{
|
||||
int i, l;
|
||||
char *s;
|
||||
|
||||
/* find last */
|
||||
for (l = -1; (i = FLAC__metadata_object_vorbiscomment_find_entry_from(block, l + 1, name)) != -1; l = i)
|
||||
;
|
||||
|
||||
if(!value || !strlen(value)) {
|
||||
if (l != -1)
|
||||
FLAC__metadata_object_vorbiscomment_delete_comment(block, l);
|
||||
return;
|
||||
}
|
||||
|
||||
s = malloc(strlen(name) + strlen(value) + 2);
|
||||
if(s) {
|
||||
FLAC__StreamMetadata_VorbisComment_Entry entry;
|
||||
|
||||
sprintf(s, "%s=%s", name, value);
|
||||
|
||||
entry.length = strlen(s);
|
||||
entry.entry = (FLAC__byte *)s;
|
||||
|
||||
if(l == -1)
|
||||
FLAC__metadata_object_vorbiscomment_insert_comment(block, block->data.vorbis_comment.num_comments, entry, /*copy=*/true);
|
||||
else
|
||||
FLAC__metadata_object_vorbiscomment_set_comment(block, l, entry, /*copy=*/true);
|
||||
free(s);
|
||||
}
|
||||
}
|
||||
|
||||
void FLAC_plugin__vorbiscomment_get(const char *filename, FLAC_Plugin__CanonicalTag *tag)
|
||||
{
|
||||
FLAC__Metadata_SimpleIterator *iterator = FLAC__metadata_simple_iterator_new();
|
||||
if(0 != iterator) {
|
||||
if(FLAC__metadata_simple_iterator_init(iterator, filename, /*read_only=*/true, /*preserve_file_stats=*/true)) {
|
||||
FLAC__bool got_vorbis_comments = false;
|
||||
do {
|
||||
if(FLAC__metadata_simple_iterator_get_block_type(iterator) == FLAC__METADATA_TYPE_VORBIS_COMMENT) {
|
||||
FLAC__StreamMetadata *block = FLAC__metadata_simple_iterator_get_block(iterator);
|
||||
if(0 != block) {
|
||||
unsigned i;
|
||||
const FLAC__StreamMetadata_VorbisComment *vc = &block->data.vorbis_comment;
|
||||
for(i = 0; i < vc->num_comments; i++) {
|
||||
if(local__vcentry_matches("artist", &vc->comments[i]))
|
||||
local__vcentry_parse_value(&vc->comments[i], &tag->composer);
|
||||
else if(local__vcentry_matches("performer", &vc->comments[i]))
|
||||
local__vcentry_parse_value(&vc->comments[i], &tag->performer);
|
||||
else if(local__vcentry_matches("album", &vc->comments[i]))
|
||||
local__vcentry_parse_value(&vc->comments[i], &tag->album);
|
||||
else if(local__vcentry_matches("title", &vc->comments[i]))
|
||||
local__vcentry_parse_value(&vc->comments[i], &tag->title);
|
||||
else if(local__vcentry_matches("tracknumber", &vc->comments[i]))
|
||||
local__vcentry_parse_value(&vc->comments[i], &tag->track_number);
|
||||
else if(local__vcentry_matches("genre", &vc->comments[i]))
|
||||
local__vcentry_parse_value(&vc->comments[i], &tag->genre);
|
||||
else if(local__vcentry_matches("description", &vc->comments[i]))
|
||||
local__vcentry_parse_value(&vc->comments[i], &tag->comment);
|
||||
else if(local__vcentry_matches("date", &vc->comments[i]))
|
||||
local__vcentry_parse_value(&vc->comments[i], &tag->year_recorded);
|
||||
}
|
||||
FLAC__metadata_object_delete(block);
|
||||
got_vorbis_comments = true;
|
||||
}
|
||||
}
|
||||
} while (!got_vorbis_comments && FLAC__metadata_simple_iterator_next(iterator));
|
||||
}
|
||||
FLAC__metadata_simple_iterator_delete(iterator);
|
||||
}
|
||||
}
|
||||
|
||||
FLAC__bool FLAC_plugin__vorbiscomment_set(const char *filename, FLAC_Plugin__CanonicalTag *tag)
|
||||
{
|
||||
FLAC__bool got_vorbis_comments = false;
|
||||
FLAC__Metadata_SimpleIterator *iterator = FLAC__metadata_simple_iterator_new();
|
||||
FLAC__StreamMetadata *block;
|
||||
|
||||
if(!iterator || !FLAC__metadata_simple_iterator_init(iterator, filename, /*read_only=*/false, /*preserve_file_stats=*/true))
|
||||
return false;
|
||||
|
||||
do {
|
||||
if(FLAC__metadata_simple_iterator_get_block_type(iterator) == FLAC__METADATA_TYPE_VORBIS_COMMENT)
|
||||
got_vorbis_comments = true;
|
||||
} while (!got_vorbis_comments && FLAC__metadata_simple_iterator_next(iterator));
|
||||
|
||||
if(!got_vorbis_comments) {
|
||||
/* create a new block */
|
||||
block = FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT);
|
||||
|
||||
if(!block) {
|
||||
FLAC__metadata_simple_iterator_delete(iterator);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
block = FLAC__metadata_simple_iterator_get_block(iterator);
|
||||
|
||||
local__vc_change_field(block, "ARTIST", tag->composer);
|
||||
local__vc_change_field(block, "PERFORMER", tag->performer);
|
||||
local__vc_change_field(block, "ALBUM", tag->album);
|
||||
local__vc_change_field(block, "TITLE", tag->title);
|
||||
local__vc_change_field(block, "TRACKNUMBER", tag->track_number);
|
||||
local__vc_change_field(block, "GENRE", tag->genre);
|
||||
local__vc_change_field(block, "DESCRIPTION", tag->comment);
|
||||
local__vc_change_field(block, "DATE", tag->year_recorded);
|
||||
|
||||
if(!got_vorbis_comments) {
|
||||
if(!FLAC__metadata_simple_iterator_insert_block_after(iterator, block, /*use_padding=*/true)) {
|
||||
FLAC__metadata_object_delete(block);
|
||||
FLAC__metadata_simple_iterator_delete(iterator);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(!FLAC__metadata_simple_iterator_set_block(iterator, block, /*use_padding=*/true)) {
|
||||
FLAC__metadata_object_delete(block);
|
||||
FLAC__metadata_simple_iterator_delete(iterator);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
FLAC__metadata_object_delete(block);
|
||||
FLAC__metadata_simple_iterator_delete(iterator);
|
||||
return true;
|
||||
}
|
||||
/* plugin_common - Routines common to several plugins
|
||||
* Copyright (C) 2002,2003,2004 Josh Coalson
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "vorbiscomment.h"
|
||||
#include "FLAC/metadata.h"
|
||||
|
||||
|
||||
static void local__add_vcentry(FLAC_Plugin__CanonicalTag *tag, FLAC__StreamMetadata_VorbisComment_Entry *entry, const char *sep)
|
||||
{
|
||||
FLAC__byte *value = memchr(entry->entry, '=', entry->length);
|
||||
int len;
|
||||
if (!value) return;
|
||||
len = value - entry->entry;
|
||||
value++;
|
||||
FLAC_plugin__canonical_add_utf8(tag, entry->entry, value, len, entry->length-len-1, sep);
|
||||
}
|
||||
|
||||
void FLAC_plugin__vorbiscomment_get(const char *filename, FLAC_Plugin__CanonicalTag *tag, const char *sep)
|
||||
{
|
||||
FLAC__Metadata_SimpleIterator *iterator = FLAC__metadata_simple_iterator_new();
|
||||
if(0 != iterator) {
|
||||
if(FLAC__metadata_simple_iterator_init(iterator, filename, /*read_only=*/true, /*preserve_file_stats=*/true)) {
|
||||
FLAC__bool got_vorbis_comments = false;
|
||||
do {
|
||||
if(FLAC__metadata_simple_iterator_get_block_type(iterator) == FLAC__METADATA_TYPE_VORBIS_COMMENT) {
|
||||
FLAC__StreamMetadata *block = FLAC__metadata_simple_iterator_get_block(iterator);
|
||||
if(0 != block) {
|
||||
unsigned i;
|
||||
const FLAC__StreamMetadata_VorbisComment *vc = &block->data.vorbis_comment;
|
||||
|
||||
for(i = 0; i < vc->num_comments; i++)
|
||||
local__add_vcentry(tag, vc->comments+i, sep);
|
||||
|
||||
FLAC__metadata_object_delete(block);
|
||||
got_vorbis_comments = true;
|
||||
}
|
||||
}
|
||||
} while (!got_vorbis_comments && FLAC__metadata_simple_iterator_next(iterator));
|
||||
}
|
||||
FLAC__metadata_simple_iterator_delete(iterator);
|
||||
}
|
||||
}
|
||||
|
||||
FLAC__bool FLAC_plugin__vorbiscomment_set(const char *filename, FLAC_Plugin__CanonicalTag *tag)
|
||||
{
|
||||
FLAC__bool got_vorbis_comments = false, result;
|
||||
FLAC__Metadata_SimpleIterator *iterator = FLAC__metadata_simple_iterator_new();
|
||||
FLAC__StreamMetadata *block;
|
||||
FLAC__tag_iterator it;
|
||||
unsigned position = 0;
|
||||
|
||||
if (!iterator || !FLAC__metadata_simple_iterator_init(iterator, filename, /*read_only=*/false, /*preserve_file_stats=*/true))
|
||||
return false;
|
||||
|
||||
do {
|
||||
if(FLAC__metadata_simple_iterator_get_block_type(iterator) == FLAC__METADATA_TYPE_VORBIS_COMMENT)
|
||||
got_vorbis_comments = true;
|
||||
} while (!got_vorbis_comments && FLAC__metadata_simple_iterator_next(iterator));
|
||||
|
||||
if(!got_vorbis_comments) {
|
||||
/* create a new block */
|
||||
block = FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT);
|
||||
|
||||
if(!block) {
|
||||
FLAC__metadata_simple_iterator_delete(iterator);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
block = FLAC__metadata_simple_iterator_get_block(iterator);
|
||||
|
||||
FLAC__metadata_object_vorbiscomment_resize_comments(block, FLAC_plugin__canonical_get_count(tag));
|
||||
|
||||
for (it=FLAC_plugin__canonical_first(tag); it; it=FLAC_plugin__canonical_next(it))
|
||||
{
|
||||
FLAC__StreamMetadata_VorbisComment_Entry entry;
|
||||
/* replace entry */
|
||||
entry.entry = FLAC_plugin__canonical_get_formatted(it);
|
||||
entry.length = strlen(entry.entry);
|
||||
FLAC__metadata_object_vorbiscomment_set_comment(block, position++, entry, /*copy=*/false);
|
||||
}
|
||||
|
||||
if (!got_vorbis_comments)
|
||||
result = FLAC__metadata_simple_iterator_insert_block_after(iterator, block, /*use_padding=*/true);
|
||||
else
|
||||
result = FLAC__metadata_simple_iterator_set_block(iterator, block, /*use_padding=*/true);
|
||||
|
||||
FLAC__metadata_object_delete(block);
|
||||
FLAC__metadata_simple_iterator_delete(iterator);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
#include "canonical_tag.h"
|
||||
#include "FLAC/ordinals.h"
|
||||
|
||||
void FLAC_plugin__vorbiscomment_get(const char *filename, FLAC_Plugin__CanonicalTag *tag);
|
||||
void FLAC_plugin__vorbiscomment_get(const char *filename, FLAC_Plugin__CanonicalTag *tag, const char *sep);
|
||||
FLAC__bool FLAC_plugin__vorbiscomment_set(const char *filename, FLAC_Plugin__CanonicalTag *tag);
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user