diff options
Diffstat (limited to 'src/libapetag/id3v2_read.c')
-rwxr-xr-x | src/libapetag/id3v2_read.c | 385 |
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 |