aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/libapetag/id3v2_read.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libapetag/id3v2_read.c')
-rwxr-xr-xsrc/libapetag/id3v2_read.c385
1 files changed, 385 insertions, 0 deletions
diff --git a/src/libapetag/id3v2_read.c b/src/libapetag/id3v2_read.c
new file mode 100755
index 0000000..f4c8a64
--- /dev/null
+++ b/src/libapetag/id3v2_read.c
@@ -0,0 +1,385 @@
+/********************************************************************
+*
+* Copyright (c) 2002 Artur Polaczynski (Ar't) All rights reserved.
+* <artii@o2.pl> LGPL-2.1
+* $ArtId: id3v2_read.c,v 1.16 2003/04/13 11:24:10 art Exp $
+********************************************************************/
+/*
+ * This program 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.
+ *
+ * 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser 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 ID3V2_READ
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <stdarg.h>
+#include <string.h>
+#include <limits.h>
+#include <assert.h>
+#include <math.h>
+#ifndef __BORLANDC__
+# include <unistd.h>
+#endif
+
+#include "apetaglib.h"
+#include <id3.h>
+
+struct id3vtwo2ape {
+ ID3_FrameID frame; //ID3FID_ALBUM etc
+ ID3_FieldID field_type; //ID3FN_TEXT etc
+ const char *APEName;
+ int special; // 0-no 1-???
+};
+
+#define APETAG_TYPE_COMMENT 1
+#define APETAG_TYPE_USER 2
+#define APETAG_TYPE_GENRE 3
+
+
+struct id3vtwo2ape convert[] = {
+ {ID3FID_ALBUM, ID3FN_TEXT, APE_TAG_FIELD_ALBUM,0},
+ {ID3FID_BAND, ID3FN_TEXT, "Band",0},
+ {ID3FID_BPM, ID3FN_TEXT, "BPM",0},
+ {ID3FID_COMPOSER, ID3FN_TEXT, APE_TAG_FIELD_COMPOSER,0},
+ {ID3FID_CONDUCTOR, ID3FN_TEXT, APE_TAG_FIELD_CONDUCTOR,0},
+ {ID3FID_CONTENTGROUP, ID3FN_TEXT, "Content Group",0},
+ {ID3FID_COPYRIGHT, ID3FN_TEXT, APE_TAG_FIELD_COPYRIGHT,0},
+ {ID3FID_DATE, ID3FN_TEXT, APE_TAG_FIELD_RECORDDATE,0},
+ {ID3FID_ENCODEDBY, ID3FN_TEXT, "Encoded By",0},
+ {ID3FID_ENCODERSETTINGS, ID3FN_TEXT, "Encoder",0},
+ {ID3FID_FILEOWNER, ID3FN_TEXT, "File Owner",0},
+ {ID3FID_FILETYPE, ID3FN_TEXT, "File Type",0},
+ {ID3FID_INITIALKEY, ID3FN_TEXT, "Initial Key",0},
+ {ID3FID_ISRC, ID3FN_TEXT, APE_TAG_FIELD_ISRC,0},
+ {ID3FID_LANGUAGE, ID3FN_TEXT, "Language",0},
+ {ID3FID_LEADARTIST, ID3FN_TEXT, APE_TAG_FIELD_ARTIST,0},
+ {ID3FID_LYRICIST, ID3FN_TEXT, "Lyricist",0},
+ {ID3FID_MEDIATYPE, ID3FN_TEXT, APE_TAG_FIELD_MEDIA,0},
+ {ID3FID_MIXARTIST, ID3FN_TEXT, "Mix Artist",0},
+ {ID3FID_NETRADIOOWNER, ID3FN_TEXT, "Internet Radio Owner",0},
+ {ID3FID_NETRADIOSTATION, ID3FN_TEXT, "Internet Radio Station",0},
+ {ID3FID_ORIGALBUM, ID3FN_TEXT, "Original Album",0},
+ {ID3FID_ORIGARTIST, ID3FN_TEXT, "Original Artist",0},
+ {ID3FID_ORIGFILENAME, ID3FN_TEXT, "Original Filename",0},
+ {ID3FID_ORIGLYRICIST, ID3FN_TEXT, "Original Lyricist",0},
+ {ID3FID_ORIGYEAR, ID3FN_TEXT, "Original Artist",0},
+ {ID3FID_PARTINSET, ID3FN_TEXT, "Part",0},
+ {ID3FID_PLAYLISTDELAY, ID3FN_TEXT, "Playlist Delay",0},
+ {ID3FID_PUBLISHER, ID3FN_TEXT, APE_TAG_FIELD_PUBLISHER,0},
+ {ID3FID_RECORDINGDATES, ID3FN_TEXT, APE_TAG_FIELD_RECORDDATE,0},
+ {ID3FID_SIZE, ID3FN_TEXT, "Size",0},
+// {ID3FID_SONGLEN, ID3FN_TEXT, "Song Length",0}, // don't like this in apetag
+ {ID3FID_SUBTITLE, ID3FN_TEXT, APE_TAG_FIELD_SUBTITLE,0},
+ {ID3FID_TIME, ID3FN_TEXT, "Time",0},
+ {ID3FID_TITLE, ID3FN_TEXT, APE_TAG_FIELD_TITLE,0},
+ {ID3FID_TRACKNUM, ID3FN_TEXT, APE_TAG_FIELD_TRACK,0},
+ {ID3FID_YEAR, ID3FN_TEXT, APE_TAG_FIELD_YEAR,0},
+
+ {ID3FID_WWWAUDIOFILE, ID3FN_URL , APE_TAG_FIELD_FILE_URL,0},
+ {ID3FID_WWWARTIST, ID3FN_URL , APE_TAG_FIELD_ARTIST_URL,0},
+ {ID3FID_WWWAUDIOSOURCE, ID3FN_URL , "Source URL",0},
+ {ID3FID_WWWCOMMERCIALINFO, ID3FN_URL , APE_TAG_FIELD_BUY_URL,0},
+ {ID3FID_WWWCOPYRIGHT, ID3FN_URL , APE_TAG_FIELD_COPYRIGHT_URL,0},
+ {ID3FID_WWWPUBLISHER, ID3FN_URL , APE_TAG_FIELD_PUBLISHER_URL,0},
+ {ID3FID_WWWPAYMENT, ID3FN_URL , "Payment",0},
+ {ID3FID_WWWRADIOPAGE, ID3FN_URL , "Web Radio URL",0},
+
+ {ID3FID_COMMENT, ID3FN_TEXT, APE_TAG_FIELD_COMMENT, APETAG_TYPE_COMMENT},
+ {ID3FID_UNSYNCEDLYRICS, ID3FN_TEXT, APE_TAG_FIELD_LYRICS, APETAG_TYPE_COMMENT},
+ {ID3FID_USERTEXT, ID3FN_TEXT, "dummy", APETAG_TYPE_USER},
+ {ID3FID_WWWUSER, ID3FN_URL , APE_TAG_FIELD_RELATED_URL, APETAG_TYPE_USER},
+ {ID3FID_CONTENTTYPE, ID3FN_TEXT, APE_TAG_FIELD_GENRE, APETAG_TYPE_GENRE},
+
+
+
+// {ID3FID_PICTURE, ID3FN_DATA, ,0},
+// {ID3FID_SYNCEDLYRICS, ID3FN_DATA, APE_TAG_FIELD_LYRICS,0},
+// {ID3FID_INVOLVEDPEOPLE, ID3FN_DATA, "Involved People",0}, // type ?
+// {ID3FID_CDID, ID3FN_DATA, "CDID",0}, // ???
+// {ID3FID_TERMSOFUSE, ID3FN_TEXT, "Terms Of Use",0}, // type ?
+};
+
+int
+libapetag_convertID3v2toAPE(const ID3Frame * frame,
+ char **item_, size_t *item_len,
+ char **value_, size_t *value_len,
+ unsigned long *flags);
+
+
+/*
+ use ALOCATE to alocate dynamic memory for frame value
+ this check size of frame and alocate mem and zeroed this mem
+*/
+
+#define ALOCATE(FielD,ValuE,SizeValuE) \
+ SizeValuE = ID3Field_Size(FielD); \
+ ValuE = (SizeValuE!=0) ? (char *) malloc((SizeValuE)+1) : NULL ; \
+ if ((SizeValuE)!=0) ValuE[0] = '\0';
+/*
+ ALOCATE_ITEM its the same ase ALOCATE but for frame name (Item)
+*/
+#define ALOCATE_ITEM(IteM, APENamE, ItemSizE) \
+ ItemSizE = strlen(APENamE) ; \
+ IteM = (ItemSizE!=0) ? (char *) malloc((ItemSizE)+1) : NULL ; \
+ if ((ItemSizE)!=0) IteM[0] = '\0';
+
+int
+libapetag_convertID3v2toAPE (const ID3Frame * frame,
+ char **item_, size_t * item_len,
+ char **value_, size_t * value_len,
+ unsigned long *flags)
+{
+ ID3Field *text;
+ ID3Field *desc;
+ ID3Field *url;
+// ID3Field *bin; // will be implemented some day
+
+ char *item = NULL;
+ char *value = NULL;
+
+ ID3_FrameID frameid = ID3Frame_GetID (frame);
+ unsigned int i;
+
+ *flags = ITEM_TEXT;
+
+ for (i = 0; i < sizeof (convert) / sizeof (struct id3vtwo2ape); i++)
+ if (frameid == convert[i].frame)
+ break;
+
+
+ if (convert[i].field_type == ID3FN_TEXT) {
+ switch (convert[i].special) {
+ case APETAG_TYPE_COMMENT: /* Comments and unsynced lyrics */
+ if ((text = ID3Frame_GetField(frame, ID3FN_TEXT)) != NULL) {
+ ALOCATE(text, value, *value_len);
+ ID3Field_GetASCII(text, value, *value_len);
+ }
+ ALOCATE_ITEM(item, convert[i].APEName, *item_len);
+ strncpy(item, convert[i].APEName, *item_len);
+ item[*item_len]='\0';
+ //break;
+ if ((text = ID3Frame_GetField (frame, ID3FN_DESCRIPTION)) != NULL) {
+ char *value_ds=NULL;
+ int value_len2;
+ if (ID3Field_Size(text) != 0) {
+ ALOCATE(text, value_ds, value_len2);
+ ID3Field_GetASCII(text, value_ds, value_len2);
+ if ( strcmp(value_ds, STR_V1_COMMENT_DESC) == 0 ) {
+ value_len2 = 0;
+ value[0]='\0';
+ } else {
+ item = (char *) realloc( item, (*item_len) + value_len2 + 3);
+ item[(*item_len)++]='-'; item[(*item_len)]='\0';
+ strncpy(item + (*item_len),value_ds ,(value_len2 + 1));
+ (*item_len)+=value_len2;
+ }
+ free(value_ds);
+ }
+ }
+ break;
+
+ case APETAG_TYPE_USER: /* User texts */
+ if ((text = ID3Frame_GetField(frame, ID3FN_TEXT)) != NULL) {
+ ALOCATE(text, value, *value_len);
+ ID3Field_GetASCII(text, value, *value_len);
+ }
+ if ((desc = ID3Frame_GetField(frame, ID3FN_DESCRIPTION)) != NULL) {
+ ALOCATE(desc, item, *item_len);
+ ID3Field_GetASCII(desc, item, *item_len);
+ }
+ break;
+
+ case APETAG_TYPE_GENRE: /* genre */
+ if ((text = ID3Frame_GetField(frame, ID3FN_TEXT)) != NULL) {
+ char *p;
+ int j;
+ ALOCATE(text, value, *value_len);
+ ID3Field_GetASCII(text, value, *value_len);
+ ALOCATE_ITEM(item, convert[i].APEName, *item_len);
+ strncpy(item, convert[i].APEName, *item_len);
+ value[*value_len]='\0';
+ p = value;
+ if (*p == '(') {
+ p++;
+ while (*p && (*p >= '0' && *p <= '9'))
+ p++;
+ if (*p && *p == ')') {
+ p++;
+ } else {
+ p = value;
+ }
+ *value_len -= (p-value); // corect lenght of frame
+ if (*p != '\0') { // copy in place
+ for (j = 0; *p != '\0'; j++) {
+ value[j] = *p;
+ p++;
+ }
+ value[j] = '\0';
+ }
+ }
+ }
+ break;
+
+ default: /* normal text tags */
+ if ((text = ID3Frame_GetField(frame, ID3FN_TEXT)) != NULL) {
+ ALOCATE(text, value, *value_len);
+ ID3Field_GetASCII(text, value, *value_len);
+ ALOCATE_ITEM(item, convert[i].APEName, *item_len);
+ strncpy(item, convert[i].APEName, *item_len);
+ }
+ break;
+
+ } /* <- switch( convert[i].special ) */
+
+ item[*item_len]='\0';
+ value[*value_len]='\0';
+ } else
+ if (convert[i].field_type == ID3FN_URL) {
+ *flags = ITEM_URL;
+ /* TODO: set ape_tag_URL in flag */
+ /* user url */
+ if (convert[i].special == APETAG_TYPE_USER) {
+ if ((url = ID3Frame_GetField(frame, ID3FN_URL)) != NULL) {
+ ALOCATE(url, value, *value_len);
+ ID3Field_GetASCII(url, value, *value_len);
+ }
+ if ((desc = ID3Frame_GetField(frame, ID3FN_DESCRIPTION)) != NULL) {
+ ALOCATE(desc, item, *item_len);
+ ID3Field_GetASCII(desc, item, *item_len);
+ }
+ /* normal url */
+ } else {
+ if ((url = ID3Frame_GetField (frame, ID3FN_URL)) != NULL) {
+ ALOCATE(url, value, *value_len);
+ ID3Field_GetASCII(url, value, *value_len);
+ ALOCATE_ITEM(item, convert[i].APEName, *item_len);
+ strncpy(item, convert[i].APEName, *item_len);
+ }
+ }
+
+ item[*item_len]='\0';
+ value[*value_len]='\0';
+ } else { //convert[i].field_type
+ item = NULL;
+ value = NULL;
+ PRINT_D (">id3v2_read>other\n");
+ }
+ *item_ = item;
+ *value_ = value;
+
+ if (!(value==NULL || (*value_len)==0) && value[(*value_len)-1]=='\0')
+ (*value_len)--;
+
+ return 0;
+}
+
+// Reads ID3v2.x tag
+// idea of this come from "tag" by Case <case@mobiili.net>
+int readtag_id3v2 ( apetag *mem_cnt, char* fileName )
+{
+ ID3Tag* tag;
+ ID3Frame* frame;
+ ID3TagIterator* iter;
+ char* item = NULL;
+ int itemSize;
+ char* value = NULL;
+ int valueSize;
+ unsigned long flags;
+
+ // first - check of id3tag v2 and init
+ if ( (tag = ID3Tag_New ()) == NULL )
+ return 1;
+ // on some casses its weerrryyy slooowwwwlyyy 65k file take 2-5 sec
+ ID3Tag_LinkWithFlags ( tag, fileName, ID3TT_ID3V2 );
+
+ if ( tag == NULL ) {
+ ID3Tag_Delete (tag);
+ return 0;
+ }
+
+ if ( !ID3Tag_HasTagType ( tag, ID3TT_ID3V2 ) ) {
+ ID3Tag_Delete (tag);
+ return 0;
+ }
+
+ if ( (iter = ID3Tag_CreateIterator (tag)) == NULL ) {
+ ID3Tag_Delete (tag);
+ return 0;
+ }
+
+ while ( (frame = ID3TagIterator_GetNext (iter)) != NULL ) {
+
+ libapetag_convertID3v2toAPE ( frame, &item, &itemSize, &value, &valueSize, &flags);
+
+ if ( !item || !value || item[0] == '\0' || value[0] == '\0' )
+ continue;
+
+ if ( !value || value[0] != '\0' ) {
+ PRINT_D4(">id3v2_read>[i%i]%s: [v%i]'%s'\n",itemSize,item,valueSize,value);
+ if ( apefrm_getstr (mem_cnt, item) == NULL ) /* noreplece !!! */
+ apefrm_add_bin (mem_cnt, flags, itemSize, item, valueSize ,value);
+ }
+ free ( value );
+ free ( item );
+ }
+
+ ID3TagIterator_Delete (iter);
+ ID3Tag_Delete (tag);
+
+ return 0;
+}
+
+#endif // ID3V2_READ
+
+
+
+#if 0
+static ID3_FrameDef ID3_FrameDefs[] =
+{
+ /* frames to implement */
+ // short long
+ // frame id id id field defs description
+ {ID3FID_AUDIOCRYPTO, "CRA", "AENC",ID3FD_Unimplemented, "Audio encryption"},
+ {ID3FID_BUFFERSIZE, "BUF", "RBUF",ID3FD_Unimplemented, "Recommended buffer size"},
+ {ID3FID_CDID, "MCI", "MCDI",ID3FD_Unimplemented, "Music CD identifier"},
+ {ID3FID_COMMERCIAL, "" , "COMR",ID3FD_Unimplemented, "Commercial"},
+ {ID3FID_CRYPTOREG, "" , "ENCR",ID3FD_Registration, "Encryption method registration"},
+ {ID3FID_EQUALIZATION, "EQU", "EQUA",ID3FD_Unimplemented, "Equalization"},
+ {ID3FID_EVENTTIMING, "ETC", "ETCO",ID3FD_Unimplemented, "Event timing codes"},
+ {ID3FID_GENERALOBJECT, "GEO", "GEOB",ID3FD_GEO, "General encapsulated object"},
+ {ID3FID_GROUPINGREG, "" , "GRID",ID3FD_Registration, "Group identification registration"},
+ {ID3FID_INVOLVEDPEOPLE, "IPL", "IPLS",ID3FD_InvolvedPeople,"Involved people list"},
+ {ID3FID_LINKEDINFO, "LNK", "LINK",ID3FD_LinkedInfo, "Linked information"},
+ {ID3FID_METACOMPRESSION, "CDM", "" ,ID3FD_CDM, "Compressed data meta frame"},
+ {ID3FID_METACRYPTO, "CRM", "" ,ID3FD_Unimplemented, "Encrypted meta frame"},
+ {ID3FID_MPEGLOOKUP, "MLL", "MLLT",ID3FD_Unimplemented, "MPEG location lookup table"},
+ {ID3FID_OWNERSHIP, "" , "OWNE",ID3FD_Unimplemented, "Ownership frame"},
+ {ID3FID_PICTURE, "PIC", "APIC",ID3FD_Picture, "Attached picture"},
+ {ID3FID_PLAYCOUNTER, "CNT", "PCNT",ID3FD_PlayCounter, "Play counter"},
+ {ID3FID_POPULARIMETER, "POP", "POPM",ID3FD_Popularimeter, "Popularimeter"},
+ {ID3FID_POSITIONSYNC, "" , "POSS",ID3FD_Unimplemented, "Position synchronisation frame"},
+ {ID3FID_PRIVATE, "" , "PRIV",ID3FD_Private, "Private frame"},
+ {ID3FID_REVERB, "REV", "RVRB",ID3FD_Unimplemented, "Reverb"},
+ {ID3FID_SYNCEDLYRICS, "SLT", "SYLT",ID3FD_SyncLyrics, "Synchronized lyric/text"},
+ {ID3FID_SYNCEDTEMPO, "STC", "SYTC",ID3FD_Unimplemented, "Synchronized tempo codes"},
+ {ID3FID_TERMSOFUSE, "" , "USER",ID3FD_TermsOfUse, "Terms of use"},
+ {ID3FID_UNIQUEFILEID, "UFI", "UFID",ID3FD_UFI, "Unique file identifier"},
+ {ID3FID_VOLUMEADJ, "RVA", "RVAD",ID3FD_Unimplemented, "Relative volume adjustment"},
+
+};
+#endif // 0