📄 id3_support.cpp
字号:
// =================================================================================================// ADOBE SYSTEMS INCORPORATED// Copyright 2002-2007 Adobe Systems Incorporated// All Rights Reserved//// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms// of the Adobe license agreement accompanying it.// =================================================================================================#include "XMP_Environment.h" // ! This must be the first include.#include "XMP_Const.h"#include "ID3_Support.hpp"#include "UnicodeConversions.hpp"#include "Reconcile_Impl.hpp"#if XMP_WinBuild #pragma warning ( disable : 4996 ) // '...' was declared deprecated#endif// For more information about the id3v2 specification// Please refer to http://www.id3.org/develop.htmlnamespace ID3_Support { char Genres[128][32]={ "Blues", // 0 "Classic Rock", // 1 "Country", // 2 "Dance", "Disco", "Funk", "Grunge", "Hip-Hop", "Jazz", // 8 "Metal", "New Age", // 10 "Oldies", "Other", // 12 "Pop", "R&B", "Rap", "Reggae", // 16 "Rock", // 17 "Techno", "Industrial", "Alternative", "Ska", "Death Metal", "Pranks", "Soundtrack", // 24 "Euro-Techno", "Ambient", "Trip-Hop", "Vocal", "Jazz+Funk", "Fusion", "Trance", "Classical", // 32 "Instrumental", "Acid", "House", "Game", "Sound Clip", "Gospel", "Noise", "AlternRock", "Bass", "Soul", //42 "Punk", "Space", "Meditative", "Instrumental Pop", "Instrumental Rock", "Ethnic", "Gothic", "Darkwave", "Techno-Industrial", "Electronic", "Pop-Folk", "Eurodance", "Dream", "Southern Rock", "Comedy", "Cult", "Gangsta", "Top 40", "Christian Rap", "Pop/Funk", "Jungle", "Native American", "Cabaret", "New Wave", // 66 "Psychadelic", "Rave", "Showtunes", "Trailer", "Lo-Fi", "Tribal", "Acid Punk", "Acid Jazz", "Polka", "Retro", "Musical", "Rock & Roll", "Hard Rock", "Folk", // 80 "Folk-Rock", "National Folk", "Swing", "Fast Fusion", "Bebob", "Latin", "Revival", "Celtic", "Bluegrass", // 89 "Avantgarde", "Gothic Rock", "Progressive Rock", "Psychedelic Rock", "Symphonic Rock", "Slow Rock", "Big Band", "Chorus", "Easy Listening", "Acoustic", "Humour", // 100 "Speech", "Chanson", "Opera", "Chamber Music", "Sonata", "Symphony", "Booty Bass", "Primus", "Porn Groove", "Satire", "Slow Jam", "Club", "Tango", "Samba", "Folklore", "Ballad", "Power Ballad", "Rhythmic Soul", "Freestyle", "Duet", "Punk Rock", "Drum Solo", "A capella", "Euro-House", "Dance Hall", "Unknown" // 126 }; // Some types #ifndef XMP_Int64 typedef unsigned long long XMP_Int64; #endif static bool FindXMPFrame(LFA_FileRef inFileRef, XMP_Int64 &posXMP, XMP_Int64 &posPAD, unsigned long &dwExtendedTag, unsigned long &dwLen); static unsigned long SkipExtendedHeader(LFA_FileRef inFileRef, XMP_Uns8 bVersion, XMP_Uns8 flag); static bool GetFrameInfo(LFA_FileRef inFileRef, XMP_Uns8 bVersion, char *strFrameID, XMP_Uns8 &cflag1, XMP_Uns8 &cflag2, unsigned long &dwSize); static bool ReadSize(LFA_FileRef inFileRef, XMP_Uns8 bVersion, unsigned long &dwSize); static unsigned long CalculateSize(XMP_Uns8 bVersion, unsigned long dwSizeIn); static bool LoadTagHeaderAndUnknownFrames(LFA_FileRef inFileRef, char *strBuffer, bool fRecon, unsigned long &posPad); #define GetFilePosition(file) LFA_Seek ( file, 0, SEEK_CUR ) const unsigned long k_dwTagHeaderSize = 10; const unsigned long k_dwFrameHeaderSize = 10; const unsigned long k_dwXMPLabelSize = 4; // 4 (size of "XMP\0")// ID3v2 flags %abcd0000// Where:// a - Unsynchronisation// b - Extended header// c - Experimental indicator// d - Footer present const unsigned char flagUnsync = 0x80; // (MSb) const unsigned char flagExt = 0x40; const unsigned char flagExp = 0x20; const unsigned char flagFooter = 0x10;#ifndef Trace_ID3_Support #define Trace_ID3_Support 0#endif// =================================================================================================#if XMP_WinBuild #define stricmp _stricmp#else static int stricmp ( const char * left, const char * right ) // Case insensitive ASCII compare. { char chL = *left; // ! Allow for 0 passes in the loop (one string is empty). char chR = *right; // ! Return -1 for stricmp ( "a", "Z" ). for ( ; (*left != 0) && (*right != 0); ++left, ++right ) { chL = *left; chR = *right; if ( chL == chR ) continue; if ( ('A' <= chL) && (chL <= 'Z') ) chL |= 0x20; if ( ('A' <= chR) && (chR <= 'Z') ) chR |= 0x20; if ( chL != chR ) break; } if ( chL == chR ) return 0; if ( chL < chR ) return -1; return 1; }#endif// =================================================================================================// *** Load Scenario:// - Check for id3v2 tag//// - Parse through the frame for "PRIV" + UTF8 Encoding + "XMP"//// - If found, load it.bool GetMetaData ( LFA_FileRef inFileRef, char* buffer, unsigned long* pBufferSize, ::XMP_Int64* fileOffset ){ if ( pBufferSize == 0 ) return false; unsigned long dwSizeIn = *pBufferSize; *pBufferSize = 0; XMP_Int64 posXMP = 0ULL, posPAD = 0ULL; unsigned long dwLen = 0, dwExtendedTag = 0; if ( ! FindXMPFrame ( inFileRef, posXMP, posPAD, dwExtendedTag, dwLen ) ) return false; // Found the XMP frame! Get the rest of frame into the buffer unsigned long dwXMPBufferLen = dwLen - k_dwXMPLabelSize; *pBufferSize = dwXMPBufferLen; if ( fileOffset != 0 ) *fileOffset = posXMP + k_dwXMPLabelSize; if ( buffer != 0 ) { // Seek 4 bytes ahead to get the XMP data. LFA_Seek ( inFileRef, posXMP+k_dwXMPLabelSize, SEEK_SET ); if ( dwXMPBufferLen > dwSizeIn ) dwXMPBufferLen = dwSizeIn; LFA_Read ( inFileRef, buffer, dwXMPBufferLen ); // Get the XMP frame } return true;}// =================================================================================================bool FindFrame ( LFA_FileRef inFileRef, char* strFrame, XMP_Int64 & posFrame, unsigned long & dwLen ){ // Taking into account that the first Tag is the ID3 tag bool fReturn = false; LFA_Seek ( inFileRef, 0ULL, SEEK_SET ); #if Trace_ID3_Support fprintf ( stderr, "ID3_Support::FindFrame : Looking for %s\n", strFrame ); #endif // Read the tag name char szID[4] = {"xxx"}; long bytesRead = LFA_Read ( inFileRef, szID, 3 ); if ( bytesRead == 0 ) return fReturn; // Check for "ID3" if ( strcmp ( szID, "ID3" ) != 0 ) return fReturn; // Read the version, flag and size XMP_Uns8 v1 = 0, v2 = 0, flags = 0; unsigned long dwTagSize = 0; if ( ! GetTagInfo ( inFileRef, v1, v2, flags, dwTagSize ) ) return fReturn; if ( dwTagSize == 0 ) return fReturn; if ( v1 > 4 ) return fReturn; // We don't support anything newer than id3v2 4.0 // If there's an extended header, ignore it XMP_Int32 dwExtendedTag = SkipExtendedHeader(inFileRef, v1, flags); dwTagSize -= dwExtendedTag; // Enumerate through the frames XMP_Int64 posCur = 0ULL; posCur = GetFilePosition ( inFileRef ); XMP_Int64 posEnd = posCur + dwTagSize; while ( posCur < posEnd ) { char szFrameID[5] = {"xxxx"}; unsigned long dwFrameSize = 0; XMP_Uns8 cflag1 = 0, cflag2 = 0; // Get the next frame if ( ! GetFrameInfo ( inFileRef, v1, szFrameID, cflag1, cflag2, dwFrameSize ) ) break; // Are we in a padding frame? if ( dwFrameSize == 0 ) break; // Is it the Frame we're looking for? if ( strcmp ( szFrameID, strFrame ) == 0 ) { posFrame = GetFilePosition ( inFileRef ); dwLen = dwFrameSize; fReturn = true; break; } else { // Jump to the next frame LFA_Seek ( inFileRef, dwFrameSize, SEEK_CUR ); } posCur = GetFilePosition ( inFileRef ); } #if Trace_ID3_Support if ( fReturn ) { fprintf ( stderr, " Found %s, offset %d, length %d\n", strFrame, (long)posFrame, dwLen ); } #endif return fReturn;}// =================================================================================================bool GetFrameData ( LFA_FileRef inFileRef, char* strFrame, char* buffer, unsigned long &dwBufferSize ){ char strData[TAG_MAX_SIZE+4]; // Plus 4 for two worst case UTF-16 nul terminators. size_t sdPos = 0; // Offset within strData to the value. memset ( &strData[0], 0, sizeof(strData) ); if ( (buffer == 0) || (dwBufferSize > TAG_MAX_SIZE) ) return false; const unsigned long dwSizeIn = dwBufferSize; XMP_Int64 posFrame = 0ULL; unsigned long dwLen = 0; XMP_Uns8 bEncoding = 0; // Find the frame if ( ! FindFrame ( inFileRef, strFrame, posFrame, dwLen ) ) return false; #if Trace_ID3_Support fprintf ( stderr, " Getting frame data\n" ); #endif if ( dwLen <= 0 ) { dwBufferSize = 1; buffer[0] = 0; } else { // Get the value for a typical text frame, having an encoding byte followed by the value. // COMM frames are special, see below. First get encoding, and the frame data into strData. dwBufferSize = dwLen - 1; // Don't count the encoding byte. // Seek to the frame LFA_Seek ( inFileRef, posFrame, SEEK_SET ); // Read the Encoding LFA_Read ( inFileRef, &bEncoding, 1 ); if ( bEncoding > 3 ) return false; // Get the frame if ( dwBufferSize > dwSizeIn ) dwBufferSize = dwSizeIn; if ( dwBufferSize >= TAG_MAX_SIZE ) return false; // No room for data. LFA_Read ( inFileRef, &strData[0], dwBufferSize ); if ( strcmp ( strFrame, "COMM" ) == 0 ) { // A COMM frame has a 3 byte language tag, then an encoded and nul terminated description // string, then the encoded value string. Set dwOffset to the offset to the value. unsigned long dwOffset = 3; // Skip the 3 byte language code.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -