blob: 39bf3568cce50c150e3c6e25fada30e16c064ea2 [file] [log] [blame]
/* ------------------------------------------------------------------
* Copyright (C) 2008 PacketVideo
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied.
* See the License for the specific language governing permissions
* and limitations under the License.
* -------------------------------------------------------------------
*/
// -*- c++ -*-
// = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
// A U D I O M P 3 G E T I D 3 I N F O
// = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
/**
* @file audiogetid3info.cpp
* @brief This include file contains the methods to obtain the required
* ID3V1 or ID3V2 information from a specified file. The various tasks it does
* to get the ID3 data are reading from the file, determining the ID3
* version, checking for a valid ID3 frame type, and extracting the ID3
* frame information.
*/
//----------------------------------------------------------------------------
// INCLUDES
//----------------------------------------------------------------------------
#include "audiogetid3info.h"
#include "oscl_mem.h"
#include "oscl_stdstring.h"
#include "oscl_utf8conv.h"
//----------------------------------------------------------------------------
// MACROS
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
// CONSTANTS
//----------------------------------------------------------------------------
static const uint8 ID3Tag[] = "ID3";
static const uint8 TAGTag[] = "TAG";
static uint32 SafeSynchIntToInt32(uint32 SafeSynchInteger)
{
uint8 * pBuf = (uint8 *) & (SafeSynchInteger);
uint8 tmpByte = 0;
int32 i = 0;
uint32 Integer = 0;
// This loop will calculate the correct size from the bytes designated for size
// It is stored as a SynchSafe Integer. This means the 8th bit is reserved in
// each byte and not used for integer precision.. The number is effectively 28
// bits in length/precision.
// Assumes: sizeof(uint32) = 4 Bytes
for (i = 0; i < 4; i++)
{
#if (OSCL_BYTE_ORDER_LITTLE_ENDIAN)
tmpByte = (uint8)(pBuf[i] & MASK127);
#elif (OSCL_BYTE_ORDER_BIG_ENDIAN)
tmpByte = pBuf[4-i-1] & MASK127;
#else
#error "Must Specify ENDIANNESS"
#endif
// now shift the data to it's correct place
Integer += tmpByte << VALID_BITS_IN_SYNC_SAFE_BYTE * i;
}
return Integer;
}
// Read in byte data and take most significant byte first
static bool readByteData(PVFile *fp, uint32 length, uint8 *data)
{
uint32 bytesRead;
bytesRead = fp->Read(data, 1, length);
if (bytesRead < (uint32)length) // read byte data failed
{
return false;
}
return true;
}
// Read in the 32 bits byte by byte and take most significant byte first
static bool read32(PVFile *fp, uint32 &data)
{
const int32 N = 4;
uint8 bytes[N];
data = 0;
int32 retVal = (int32)(fp->Read((void*)bytes, 1, N));
if (retVal < N)
{
return false;
}
for (int32 i = 0; i < N; i++)
{
data = (data << 8) | bytes[i];
}
return true;
}
// Read in the 32 bits byte by byte and take most significant byte first
static bool read24(PVFile *fp, uint32 &data)
{
const int32 N = 3;
uint8 bytes[N];
data = 0;
int32 retVal = (int32)(fp->Read((void*)bytes, 1, N));
if (retVal < N)
{
return false;
}
for (int32 i = 0; i < N; i++)
{
data = (data << 8) | bytes[i];
}
return true;
}
// Read in the 8 bit byte
static bool read8(PVFile *fp, uint8 &data)
{
data = 0;
int32 retVal = (int32)(fp->Read((void*) & data, 1, 1));
if (retVal < 1)
{
return false;
}
return true;
}
//----------------------------------------------------------------------------
// FUNCTION NAME: CID3TagParser::CID3TagParser()
//----------------------------------------------------------------------------
// INPUT AND OUTPUT DEFINITIONS
//
// Inputs: None
//
// Outputs: None
//
// Returns: None
//
// Global Variables Used: None
//
//----------------------------------------------------------------------------
// FUNCTION DESCRIPTION
//
// This function is the constructor for the CID3TagParser class.
//
//------------------------------------------------------------------------------
CID3TagParser::CID3TagParser()
{
iTitleFoundFlag = false;
oscl_memset(&iID3TagInfo, 0, sizeof(iID3TagInfo));
iFilePtr = NULL;
}
//----------------------------------------------------------------------------
// FUNCTION NAME: CID3TagParser::~CID3TagParser
//----------------------------------------------------------------------------
// INPUT AND OUTPUT DEFINITIONS
//
// Inputs: None
//
// Outputs: None
//
// Returns: None
//
// Global Variables Used: None
//
//----------------------------------------------------------------------------
// FUNCTION DESCRIPTION
//
// This function is the destructor for the CID3TagParser class.
//
//------------------------------------------------------------------------------
OSCL_EXPORT_REF CID3TagParser::~CID3TagParser()
{
}
//----------------------------------------------------------------------------
// FUNCTION NAME: CID3TagParser::NewL()
//----------------------------------------------------------------------------
// INPUT AND OUTPUT DEFINITIONS
//
// Inputs: None
//
// Outputs: None
//
// Returns: Returns a pointer to an instance of this class
//
// Global Variables Used: None
//
//----------------------------------------------------------------------------
// FUNCTION DESCRIPTION
//
// This function is the 2nd phase constructor for this object.It also
// is to be available to application programs and other DLLs.
//
//------------------------------------------------------------------------------
OSCL_EXPORT_REF CID3TagParser* CID3TagParser::NewL()
{
OsclAuditCB myCB;
OsclMemInit(myCB);
CID3TagParser* self = OSCL_AUDIT_NEW(myCB, CID3TagParser, ());
self->ConstructL();
return self;
}
//----------------------------------------------------------------------------
// FUNCTION NAME: CID3TagParser::Delete()
//----------------------------------------------------------------------------
// INPUT AND OUTPUT DEFINITIONS
//
// Inputs: Pointer to an instance of this class
//
// Outputs: None
//
// Returns: None
//
// Global Variables Used: None
//
//----------------------------------------------------------------------------
// FUNCTION DESCRIPTION
//
// Destructor for use with NewL
//
//------------------------------------------------------------------------------
OSCL_EXPORT_REF void CID3TagParser::Delete(CID3TagParser* aObject)
{
OSCL_DELETE(aObject);
}
//----------------------------------------------------------------------------
// FUNCTION NAME: CID3TagParser::ParseTagInfo(
// TAudioMetaData& aID3MetaData)
//----------------------------------------------------------------------------
// INPUT AND OUTPUT DEFINITIONS
//
// Inputs:
// aID3MetaData - Reference to a pre-allocated TAudioMetaData structure
//
// Outputs:
// aID3MetaData - Reference to a pre-allocated TAudioMetaData structure
//
// Returns: None
//
// Global Variables Used: None
//
//----------------------------------------------------------------------------
// FUNCTION DESCRIPTION
//
// This function causes the checks for the existance of an ID3V1 or ID3V2 tag
// associated with the file under investigation. It then makes a function
// call to get the information from the tag to populate aID3MetaData.
//
//------------------------------------------------------------------------------
// CAUTION
// Leaves the File Pointer a the start of the first audio frame
//------------------------------------------------------------------------------
OSCL_EXPORT_REF int32 CID3TagParser::ParseID3TagInfo(PVFile * aFile,
TAudioMetaData& aID3MetaData)
{
iTitleFoundFlag = false;
int32 iCurrentFilePosn = 0;
// Initialize the ID3 elements to be unknown
aID3MetaData.iTitle.iFormat = TAudioMetaData::FORMAT_INVALID;
aID3MetaData.iArtist.iFormat = TAudioMetaData::FORMAT_INVALID;
aID3MetaData.iAlbum.iFormat = TAudioMetaData::FORMAT_INVALID;
aID3MetaData.iSet.iFormat = TAudioMetaData::FORMAT_INVALID;
aID3MetaData.iYear.iFormat = TAudioMetaData::FORMAT_INVALID;
aID3MetaData.iComment.iFormat = TAudioMetaData::FORMAT_INVALID;
aID3MetaData.iCopyright.iFormat = TAudioMetaData::FORMAT_INVALID;
aID3MetaData.iGenre.iFormat = TAudioMetaData::FORMAT_INVALID;
aID3MetaData.iTrackNumber.iFormat = TAudioMetaData::FORMAT_INVALID;
if (aFile != NULL)
{
iFilePtr = aFile;
// SEEK TO THE END OF THE FILE AND GET FILE SIZE
iCurrentFilePosn = iFilePtr->Tell();
if (iCurrentFilePosn == -1)
{
return PVID3PARSER_FILE_OPERATION_FAILED;
}
if (iFilePtr->Seek(0, Oscl_File::SEEKEND) == -1)
{
return PVID3PARSER_FILE_OPERATION_FAILED;
}
aID3MetaData.iFileSizeInBytes = iFilePtr->Tell();
if (aID3MetaData.iFileSizeInBytes == (uint32) - 1)
{
return PVID3PARSER_FILE_OPERATION_FAILED;
}
if (iFilePtr->Seek(iCurrentFilePosn, Oscl_File::SEEKSET) == -1)
{
return PVID3PARSER_FILE_OPERATION_FAILED;
}
// Initialize the ID3 tag
aID3MetaData.iID3VersionType = ENoTag;
if (CheckForTagID3V2(aID3MetaData))
{
aID3MetaData.iID3VersionType = EID3V2;
iCurrentFilePosn = iFilePtr->Tell();
if (iCurrentFilePosn == -1)
{
return PVID3PARSER_FILE_OPERATION_FAILED;
}
ReadHeaderID3V2(aID3MetaData);
if (!iTitleFoundFlag)
{
if (CheckForTagID3V1(aID3MetaData))
{
ReadID3V1Tag(aID3MetaData, true);
}
}
if (iFilePtr->Seek(iCurrentFilePosn, Oscl_File::SEEKSET) == -1)
{
return PVID3PARSER_FILE_OPERATION_FAILED;
}
}
else
{
if (CheckForTagID3V1(aID3MetaData))
{
aID3MetaData.iID3VersionType = EID3V1;
ReadID3V1Tag(aID3MetaData, false);
aID3MetaData.iByteOffsetToStartOfAudioFrames = 0;
}
else // No ID3 tag was found.
{
aID3MetaData.iID3VersionType = ENoTag;
aID3MetaData.iByteOffsetToStartOfAudioFrames = 0;
}
if (iFilePtr->Seek(iCurrentFilePosn, Oscl_File::SEEKSET) == -1)
{
return PVID3PARSER_FILE_OPERATION_FAILED;
}
}
return PVID3PARSER_EVERYTHING_FINE;
}
else
{
return PVID3PARSER_FILE_OPEN_FAILED;
}
}
//----------------------------------------------------------------------------
// FUNCTION NAME: CID3TagParser::ConstructL()
//----------------------------------------------------------------------------
// INPUT AND OUTPUT DEFINITIONS
//
// Inputs: None
//
// Outputs: None
//
// Returns: None
//
// Global Variables Used: None
//
//----------------------------------------------------------------------------
// FUNCTION DESCRIPTION
//
// This function is the constructor for the CID3TagParser class.
//
//------------------------------------------------------------------------------
void CID3TagParser::ConstructL()
{
}
//----------------------------------------------------------------------------
// FUNCTION NAME: CID3TagParser::CheckForTagID3V2(TAudioMetaData& aID3MetaData)
//----------------------------------------------------------------------------
// INPUT AND OUTPUT DEFINITIONS
//
// Inputs:
// aID3MetaData - reference to a TAudioMetaData structure
//
// Outputs: None
//
// Returns:
// bool - true if Id3V2 tag present otherwise false.
//
// Global Variables Used: None
//
//----------------------------------------------------------------------------
// FUNCTION DESCRIPTION
//
// This function checks the file for the presence of ID3V2 Tag attached to
// the beginning of the file. This tag is denoted by the string "ID3"
// at the very beginning of the file.
//------------------------------------------------------------------------------
bool CID3TagParser::CheckForTagID3V2(TAudioMetaData& aID3MetaData)
{
uint8 id3Header[ID3V2_TAG_NUM_BYTES_HEADER+1] = {0};
// Make sure file is big enough to contain a tag
if (aID3MetaData.iFileSizeInBytes >= ID3V2_TAG_NUM_BYTES_HEADER)
{
if (!readByteData(iFilePtr, ID3V2_TAG_NUM_BYTES_HEADER, id3Header))
{
return false;
}
// Read in ID3 Tags at the front of the file.
if (oscl_memcmp(ID3Tag, id3Header, 3) == 0)
{
return true;
}
}
return false;
}
//----------------------------------------------------------------------------
// FUNCTION NAME: CID3TagParser::CheckForTagID3V1(TAudioMetaData& aID3MetaData)
//----------------------------------------------------------------------------
// INPUT AND OUTPUT DEFINITIONS
//
// Inputs:
// aID3MetaData - reference to a TAudioMetaData structure
//
// Outputs: None
//
// Returns:
// bool - true if Id3V1 tag present otherwise false
//
// Global Variables Used: None
//
//----------------------------------------------------------------------------
// FUNCTION DESCRIPTION
//
// This function checks the file for the presence of ID3V1 Tag. This tag is
// denoted by the string "TAG" starting 128 bytes in from the end-of-file.
//
//------------------------------------------------------------------------------
bool CID3TagParser::CheckForTagID3V1(TAudioMetaData& aID3MetaData)
{
uint8 tagHeader[ID3V1_TAG_NUM_BYTES_HEADER+1] = {0};
// Make sure file is big enough to contain a tag
if (aID3MetaData.iFileSizeInBytes >= ID3V1_MAX_NUM_BYTES_TOTAL)
{
uint32 nBytes = 0;
// Read the value at the tag position
nBytes = aID3MetaData.iFileSizeInBytes - ID3V1_MAX_NUM_BYTES_TOTAL;
if (iFilePtr->Seek(nBytes, Oscl_File::SEEKSET) == -1)
{
return false;
}
if (!readByteData(iFilePtr, ID3V1_TAG_NUM_BYTES_HEADER, tagHeader))
{
return false;
}
// Read in ID3 Tags at the front of the file.
if (oscl_memcmp(TAGTag, tagHeader, 3) == 0)
{
aID3MetaData.iMajorVersion = 1;
aID3MetaData.iMinorVersion = 0;
return true;
}
}
return false;
}
//----------------------------------------------------------------------------
// FUNCTION NAME: CID3TagParser::ReadID3V1Tag(TAudioMetaData& aID3MetaData)
//----------------------------------------------------------------------------
// INPUT AND OUTPUT DEFINITIONS
//
// Inputs:
// aID3MetaData - reference to a TAudioMetaData structure
//
// Outputs:
// aID3MetaData - reference to a TAudioMetaData structure
//
// Returns: None
//
// Global Variables Used: None
//
//----------------------------------------------------------------------------
// FUNCTION DESCRIPTION
//
// This function parses the file and populates the aID3MetaData structure when
// an ID3V1 tag is found to be attached to the file and no ID3V2 tag was
// found. The data in the ID3V1 tag can only be ASCII, so the ConvertToUnicode
// must be called for all fields read from the ID3V1 tag.
//
//----------------------------------------------------------------------------
// REQUIREMENTS
//
// The track must be declared in an ASCII character and not a numeric string.
//------------------------------------------------------------------------------
void CID3TagParser::ReadID3V1Tag(TAudioMetaData& aID3MetaData,
bool aTitleOnlyFlag)
{
char Buf[ID3V1_MAX_NUM_BYTES_FIELD_SIZE+1] = {0};
// Read and convert title
oscl_memset(Buf, 0, ID3V1_MAX_NUM_BYTES_FIELD_SIZE + 1);
if (readByteData(iFilePtr, ID3V1_MAX_NUM_BYTES_TITLE, (uint8 *)Buf) == false)
{
return;
}
Buf[ID3V1_MAX_NUM_BYTES_FIELD_SIZE] = 0;
oscl_strncpy(aID3MetaData.iTitle.pChar, Buf, oscl_strlen(Buf));
aID3MetaData.iTitle.pChar[oscl_strlen(Buf)] = 0;
if ((aID3MetaData.iID3VersionType == EID3V2) && (aTitleOnlyFlag == true))
{
aID3MetaData.iTitle.iFormat = TAudioMetaData::EISO88591_CHAR;
iTitleFoundFlag = true;
return;
}
iTitleFoundFlag = true;
if (!aTitleOnlyFlag)
{
// Set the format for title
aID3MetaData.iTitle.iFormat = TAudioMetaData::EISO88591_CHAR;
// Read and convert artist
oscl_memset(Buf, 0, ID3V1_MAX_NUM_BYTES_FIELD_SIZE + 1);
if (readByteData(iFilePtr, ID3V1_MAX_NUM_BYTES_ARTIST, (uint8*)Buf) == false)
{
return;
}
Buf[ID3V1_MAX_NUM_BYTES_ARTIST] = 0;
oscl_strncpy(aID3MetaData.iArtist.pChar, Buf, oscl_strlen(Buf));
aID3MetaData.iArtist.pChar[oscl_strlen(Buf)] = 0;
aID3MetaData.iArtist.iFormat = TAudioMetaData::EISO88591_CHAR;
// Read and convert album
oscl_memset(Buf, 0, ID3V1_MAX_NUM_BYTES_FIELD_SIZE + 1);
if (readByteData(iFilePtr, ID3V1_MAX_NUM_BYTES_ALBUM, (uint8*)Buf) == false)
{
return;
}
Buf[ID3V1_MAX_NUM_BYTES_ALBUM] = 0;
oscl_strncpy(aID3MetaData.iAlbum.pChar, Buf, oscl_strlen(Buf));
aID3MetaData.iAlbum.pChar[oscl_strlen(Buf)] = 0;
aID3MetaData.iAlbum.iFormat = TAudioMetaData::EISO88591_CHAR;
// Read and convert year
oscl_memset(Buf, 0, ID3V1_MAX_NUM_BYTES_FIELD_SIZE + 1);
if (readByteData(iFilePtr, ID3V1_MAX_NUM_BYTES_YEAR, (uint8*)Buf) == false)
{
return;
}
Buf[ID3V1_MAX_NUM_BYTES_YEAR] = 0;
oscl_strncpy(aID3MetaData.iYear.pChar, Buf, oscl_strlen(Buf));
aID3MetaData.iYear.pChar[oscl_strlen(Buf)] = 0;
aID3MetaData.iYear.iFormat = TAudioMetaData::EISO88591_CHAR;
// Read and convert comment & possibly track number
oscl_memset(Buf, 0, ID3V1_MAX_NUM_BYTES_FIELD_SIZE + 1);
if (readByteData(iFilePtr, ID3V1_MAX_NUM_BYTES_COMMENT, (uint8*)Buf) == false)
{
return;
}
if ((Buf[ID3V1_MAX_NUM_BYTES_COMMENT-2] == 0)
&& (Buf[ID3V1_MAX_NUM_BYTES_COMMENT-1] != 0))
{
// This would mean its an ID3v1.1 tag and hence has the
// the track number also, so extract it
aID3MetaData.iTrackNumber.uint8_value = (uint8)Buf[ID3V1_MAX_NUM_BYTES_COMMENT-1];
aID3MetaData.iTrackNumber.iFormat = TAudioMetaData::EBYTEVALUE_UINT8;
aID3MetaData.iMinorVersion = 1;
}
else
{
// Track number is not available
aID3MetaData.iTrackNumber.iFormat = TAudioMetaData::FORMAT_INVALID;
}
Buf[ID3V1_MAX_NUM_BYTES_COMMENT] = 0;
oscl_strncpy(aID3MetaData.iComment.pChar, Buf, oscl_strlen(Buf));
aID3MetaData.iComment.pChar[oscl_strlen(Buf)] = 0;
aID3MetaData.iComment.iFormat = TAudioMetaData::EISO88591_CHAR;
// Comment language code and comment not available in ID3v1
oscl_memset(aID3MetaData.iComment.description_pChar, 0, MAX_UNICODE_BUF_LEN_COMMENT_DESCRIPTION);
oscl_memset(aID3MetaData.iComment.langcode_pChar, 0, MAX_UNICODE_BUF_LEN_COMMENT_LANGCODE);
// Read the genre value
oscl_memset(Buf, 0, ID3V1_MAX_NUM_BYTES_FIELD_SIZE + 1);
if (readByteData(iFilePtr, ID3V1_MAX_NUM_BYTES_GENRE, (uint8*)Buf) == false)
{
return;
}
aID3MetaData.iGenre.uint8_value = (uint8)Buf[0];
aID3MetaData.iGenre.iFormat = TAudioMetaData::EBYTEVALUE_UINT8;
}
}
//----------------------------------------------------------------------------
// FUNCTION NAME: CID3TagParser::ReadHeaderID3V2(TAudioMetaData& aID3MetaData)
//----------------------------------------------------------------------------
// INPUT AND OUTPUT DEFINITIONS
//
// Inputs:
// aID3MetaData - pointer to repository for parsed data
//
// Outputs:
// aID3MetaData - pointer to repository for parsed data
//
// Returns: None
//
// Global Variables Used: None
//
//----------------------------------------------------------------------------
// FUNCTION DESCRIPTION
//
// This function parses the ID3 tag frames from the file and populates the
// aID3MetaData structure when an ID3V2 tag is found attached to the start
// of a file.
//
//------------------------------------------------------------------------------
void CID3TagParser::ReadHeaderID3V2(TAudioMetaData& aID3MetaData)
{
if (iFilePtr->Seek(0, Oscl_File::SEEKSET) == -1)
{
return;
}
// Read "ID3" tag at start of file.
uint8 identifierBuf[ID3V2_TAG_NUM_BYTES_ID];
if (readByteData(iFilePtr, ID3V2_TAG_NUM_BYTES_ID, identifierBuf) == false)
{
return;
}
// Read and convert tag versions, Major and Minor
uint8 ID3V2MajorVer, ID3V2MinorVer;
if (read8(iFilePtr, ID3V2MajorVer) == false)
{
return;
}
if (read8(iFilePtr, ID3V2MinorVer) == false)
{
return;
}
aID3MetaData.iMajorVersion = ID3V2MajorVer;
aID3MetaData.iMinorVersion = ID3V2MinorVer;
// Read and convert tag flags
if (read8(iFilePtr, iID3TagInfo.iID3V2TagFlagsV2) == false)
{
return;
}
// Read and convert tag size
if (read32(iFilePtr, iID3TagInfo.iID3V2TagSize) == false)
{
return;
}
// Now check if an extended header exists
bool extHeaderFlag = false;
if (iID3TagInfo.iID3V2TagFlagsV2 & FLAGMASK)
{
extHeaderFlag = true;
uint8 extHeader[ID3V2_TAG_EXTENDED_HEADER_TOTAL_SIZE];
if (readByteData(iFilePtr, ID3V2_TAG_EXTENDED_HEADER_TOTAL_SIZE, extHeader) == false)
{
return;
}
}
// tagSize will store the file's Id3v2 tag size
uint32 tagSize = 0;
uint32 i;
tagSize = SafeSynchIntToInt32(iID3TagInfo.iID3V2TagSize);
// set iByteOffsetToStartOfAudioFrames and it must account for the frame header
aID3MetaData.iByteOffsetToStartOfAudioFrames =
tagSize + ID3V2_TAG_NUM_BYTES_HEADER;
// Add Footer Header Size if present
if (iID3TagInfo.iID3V2TagFlagsV2 & FOOTERMASK)
{
aID3MetaData.iByteOffsetToStartOfAudioFrames += ID3V2_TAG_NUM_BYTES_FOOTER;
}
uint32 tagExtHeaderSize = 0;
// Calculate the length of the extended header.
if (extHeaderFlag)
{
tagExtHeaderSize = SafeSynchIntToInt32(iID3TagInfo.iID3V2ExtendedHeader);
aID3MetaData.iByteOffsetToStartOfAudioFrames +=
tagExtHeaderSize + ID3V2_TAG_EXTENDED_HEADER_TOTAL_SIZE;
}
TID3V2FrameType frameType;
uint32 currFrameLength;
uint32 aIDV2FrameNumBytesHeader;
i = ID3V2_TAG_NUM_BYTES_HEADER; // must account for the tag header
if (extHeaderFlag)
{
i += tagExtHeaderSize + ID3V2_TAG_EXTENDED_HEADER_TOTAL_SIZE;
}
if (ID3V2MajorVer == 0x02)
aIDV2FrameNumBytesHeader = ID3V22_FRAME_NUM_BYTES_HEADER;
else
aIDV2FrameNumBytesHeader = ID3V2_FRAME_NUM_BYTES_HEADER;
while (i <= tagSize)
{
// Read the frame header
if (iFilePtr->Seek(i, Oscl_File::SEEKSET) == -1)
{
return;
}
if (ID3V2MajorVer == 0x02)
ReadFrameHeaderID3V22(i);
else
ReadFrameHeaderID3V2(i);
if (ID3V2MajorVer == 0x04)
iID3TagInfo.iID3V2FrameSize = SafeSynchIntToInt32(iID3TagInfo.iID3V2FrameSize);
currFrameLength = 0;
currFrameLength = iID3TagInfo.iID3V2FrameSize;
if (currFrameLength > tagSize)
{
break;
}
// handle the frame header
if (ID3V2MajorVer == 0x02)
frameType = FrameSupportedID3V22();
else
frameType = FrameSupportedID3V2();
/*
* Check the byte after the frame header for indication of unicode.
* If the frame is type TLEN then it has a numeric string and do not
* make a check for unicode type.
*/
if ((frameType != ETLEN) &&
((currFrameLength > 1) && (frameType != EFrameNotSupported)))
{
uint8 unicodeCheck;
if (read8(iFilePtr, unicodeCheck) == false)
{
return;
}
if (unicodeCheck == EISO88591)
{
// This frame contains normal ASCII text strings. (ISO-8859-1)
iID3TagInfo.iTextType = EISO88591;
HandleID3V2FrameDataASCII(frameType,
i + aIDV2FrameNumBytesHeader + 1,
currFrameLength - 1,
aID3MetaData);
}
else if (unicodeCheck == EUTF16)
{
uint8 endianCheck;
// Special case for comments. The first 3 bytes are the have
// language code, which does not have any BOM
if (frameType == ECOMT)
{
uint8 endianData[4];
if (readByteData(iFilePtr, 4, endianData) == false)
{
return;
}
endianCheck = endianData[3];
}
else
{
if (read8(iFilePtr, endianCheck) == false)
{
return;
}
}
// This frame's text strings are Unicode and the frame
// does include a BOM value. (UTF-16)
iID3TagInfo.iTextType = EUTF16;
if ((endianCheck != UNICODE_LITTLE_ENDIAN_INDICATOR) &&
(endianCheck != UNICODE_BIG_ENDIAN_INDICATOR))
{
frameType = EFrameNotSupported;
break;
}
HandleID3V2FrameDataUTF16(frameType,
i + aIDV2FrameNumBytesHeader + 1,
currFrameLength - 1,
EUTF16,
aID3MetaData);
}
else if (unicodeCheck == EUTF16BE)
{
// This frame's text strings are Unicode but the frame
// does not contain a BOM(byte order mark) (UTF-16BE)
iID3TagInfo.iTextType = EUTF16BE;
// Big Endian is assumed since the frame did not specify the endian type.
HandleID3V2FrameDataUTF16(frameType,
i + aIDV2FrameNumBytesHeader + 1,
currFrameLength - 1,
EUTF16BE,
aID3MetaData);
}
else if (unicodeCheck == EUTF8)
{
// This frame's text strings are Unicode (UTF-8)
iID3TagInfo.iTextType = EUTF8;
HandleID3V2FrameDataUTF8(frameType,
i + aIDV2FrameNumBytesHeader + 1,
currFrameLength - 1,
aID3MetaData);
}
else
{
iID3TagInfo.iTextType = ENoType;
// This case is when no text type is defined in the frame.
HandleID3V2FrameDataASCII(frameType,
i + aIDV2FrameNumBytesHeader,
currFrameLength,
aID3MetaData);
}
}
else
{
if (frameType == EEND)
{
i = tagSize + 1;
}
else
{
iID3TagInfo.iTextType = ENoType;
HandleID3V2FrameDataASCII(frameType,
i + aIDV2FrameNumBytesHeader,
currFrameLength,
aID3MetaData);
}
}
i += currFrameLength + aIDV2FrameNumBytesHeader;
}
}
//----------------------------------------------------------------------------
// FUNCTION NAME: CID3TagParser::ReadFrameHeaderID3V2(uint32 aPos)
//----------------------------------------------------------------------------
// INPUT AND OUTPUT DEFINITIONS
//
// Inputs:
// aPos - position in file where frame
//
// Outputs: None
//
// Returns: None
//
// Global Variables Used: None
//
//----------------------------------------------------------------------------
// FUNCTION DESCRIPTION
//
// This function parses the frame and populates the iID3TagInfo structure
// when an ID3V2 tag is found to be attached to the file.
//
//------------------------------------------------------------------------------
void CID3TagParser::ReadFrameHeaderID3V2(uint32 aPos)
{
if (readByteData(iFilePtr, ID3V2_FRAME_NUM_BYTES_ID, iID3TagInfo.iID3V2FrameID) == false)
{
return;
}
if (read32(iFilePtr, iID3TagInfo.iID3V2FrameSize) == false)
{
return;
}
if (readByteData(iFilePtr, ID3V2_FRAME_NUM_BYTES_FLAG, iID3TagInfo.iID3V2FrameFlag) == false)
{
return;
}
iID3TagInfo.iPositionInFile = aPos;
return;
}
//----------------------------------------------------------------------------
// FUNCTION NAME: CID3TagParser::ReadFrameHeaderID3V22(uint32 aPos)
//----------------------------------------------------------------------------
// INPUT AND OUTPUT DEFINITIONS
//
// Inputs:
// aPos - position in file where frame
//
// Outputs: None
//
// Returns: None
//
// Global Variables Used: None
//
//----------------------------------------------------------------------------
// FUNCTION DESCRIPTION
//
// This function parses the frame and populates the iID3TagInfo structure
// when an ID3V2 tag is found to be attached to the file.
//
//------------------------------------------------------------------------------
void CID3TagParser::ReadFrameHeaderID3V22(uint32 aPos)
{
if (readByteData(iFilePtr, ID3V22_FRAME_NUM_BYTES_ID, iID3TagInfo.iID3V2FrameID) == false)
{
return;
}
if (read24(iFilePtr, iID3TagInfo.iID3V2FrameSize) == false)
{
return;
}
iID3TagInfo.iPositionInFile = aPos;
return;
}
//----------------------------------------------------------------------------
// FUNCTION NAME: CID3TagParser::HandleID3V2FrameDataASCII(
// TFrameTypeID3V2 aFrameType,
// uint32 aPos,
// uint32 aSize,
// TAudioMetaData& aID3MetaData)
//----------------------------------------------------------------------------
// INPUT AND OUTPUT DEFINITIONS
//
// Inputs:
// aFrameType - enumerated TFrameTypeID3V2 type - used to determine if
// Frame is supported
// aPos - position in file where frame data begins
// aSize - size of the frame data
// aID3MetaData - pointer to repository for parsed data
//
// Outputs:
// aID3MetaData - pointer to repository for parsed data
//
// Returns: None
//
// Global Variables Used: None
//
//----------------------------------------------------------------------------
// FUNCTION DESCRIPTION
//
// This function receives a ID3V2 frame and handles it accordingly. Each
// frame header is composed of 10 bytes - 4 bytes for FrameID, 4 bytes for
// FrameSize, and 2 bytes for FrameFlags, respectively. Once we have a
// frame's unique FrameID, we can handle the frame accordingly. (eg. The
// frame with FrameID = "TIT2" contains data describing the title.
// Clearly, the data in that frame should be copied to it respective
// location in aID3MetaData. The location for the data with FrameID = "TIT2"
// goes in the aID3MetaData.iTitle buffer. This line of code accomplishes our
// objective: aID3MetaData.iTitle.Copy(ptrFrameData16);
//
//------------------------------------------------------------------------------
void CID3TagParser::HandleID3V2FrameDataASCII(TID3V2FrameType aFrameType,
uint32 aPos,
uint32 aSize,
TAudioMetaData& aID3MetaData)
{
if (iFilePtr->Seek(aPos, Oscl_File::SEEKSET) == -1)
{
return;
}
// create buffers to store frame data
uint8* frameData = OSCL_ARRAY_NEW(uint8, aSize + 1);
if (frameData == NULL)
{
return;
}
uint8* ptrFrameData = frameData;
oscl_memset(frameData, 0, aSize + 1);
switch (aFrameType)
{
case ETIT2:
{
// Handle TIT2 frame
// The TIT2 frame contains data referring to the title.
if (readByteData(iFilePtr, aSize, ptrFrameData) == false)
{
OSCL_ARRAY_DELETE(ptrFrameData);
return;
}
ptrFrameData[aSize] = 0;
oscl_strncpy(aID3MetaData.iTitle.pChar, (char*)ptrFrameData, MAX_UNICODE_BUF_LEN_TITLE);
aID3MetaData.iTitle.pChar[MAX_UNICODE_BUF_LEN_TITLE-1] = 0;
aID3MetaData.iTitle.iFormat = TAudioMetaData::EISO88591_CHAR;
iTitleFoundFlag = true;
}
break;
case ETPE1:
{
// Handle TPE1 frame
// The TPE1 frame contains data referring to the artist.
if (readByteData(iFilePtr, aSize, ptrFrameData) == false)
{
OSCL_ARRAY_DELETE(ptrFrameData);
return;
}
ptrFrameData[aSize] = 0;
oscl_strncpy(aID3MetaData.iArtist.pChar, (char*)ptrFrameData, MAX_UNICODE_BUF_LEN_ARTIST);
aID3MetaData.iArtist.pChar[MAX_UNICODE_BUF_LEN_ARTIST-1] = 0;
aID3MetaData.iArtist.iFormat = TAudioMetaData::EISO88591_CHAR;
}
break;
case ETPOS:
{
// Handle TPOS/TPA frame
// The TPOS frame contains data defining if this is part of
// a multi disc set.
if (readByteData(iFilePtr, aSize, ptrFrameData) == false)
{
OSCL_ARRAY_DELETE(ptrFrameData);
return;
}
ptrFrameData[aSize] = 0;
oscl_strncpy(aID3MetaData.iSet.pChar, (char*)ptrFrameData, MAX_UNICODE_BUF_LEN_SET);
aID3MetaData.iSet.pChar[MAX_UNICODE_BUF_LEN_SET-1] = 0;
aID3MetaData.iSet.iFormat = TAudioMetaData::EISO88591_CHAR;
}
break;
case ETALB:
{
// Handle TALB frame
// The TALB frame contains data referring to the album.
if (readByteData(iFilePtr, aSize, ptrFrameData) == false)
{
OSCL_ARRAY_DELETE(ptrFrameData);
return;
}
ptrFrameData[aSize] = 0;
oscl_strncpy(aID3MetaData.iAlbum.pChar, (char*)ptrFrameData, MAX_UNICODE_BUF_LEN_ALBUM);
aID3MetaData.iAlbum.pChar[MAX_UNICODE_BUF_LEN_ALBUM-1] = 0;
aID3MetaData.iAlbum.iFormat = TAudioMetaData::EISO88591_CHAR;
}
break;
case ETCOP:
{
// Handle TCOP frame
// The TCOP frame contains data referring to the copyright.
if (readByteData(iFilePtr, aSize, ptrFrameData) == false)
{
OSCL_ARRAY_DELETE(ptrFrameData);
return;
}
ptrFrameData[aSize] = 0;
oscl_strncpy(aID3MetaData.iCopyright.pChar, (char*)ptrFrameData, MAX_UNICODE_BUF_LEN_COPYRIGHT);
aID3MetaData.iCopyright.pChar[MAX_UNICODE_BUF_LEN_COPYRIGHT-1] = 0;
aID3MetaData.iCopyright.iFormat = TAudioMetaData::EISO88591_CHAR;
}
break;
case ETCON:
{
// Handle TCON frame
// The TCON frame contains data referring to the genre.
if (readByteData(iFilePtr, aSize, ptrFrameData) == false)
{
OSCL_ARRAY_DELETE(ptrFrameData);
return;
}
ptrFrameData[aSize] = 0;
oscl_strncpy(aID3MetaData.iGenre.pChar, (char*)ptrFrameData, MAX_UNICODE_BUF_LEN_GENRE);
aID3MetaData.iGenre.pChar[MAX_UNICODE_BUF_LEN_GENRE-1] = 0;
aID3MetaData.iGenre.iFormat = TAudioMetaData::EISO88591_CHAR;
}
break;
case ETRCK:
{
// Handle TRCK frame
// The TRCK frame contains data referring to the track number.
if (readByteData(iFilePtr, aSize, ptrFrameData) == false)
{
OSCL_ARRAY_DELETE(ptrFrameData);
return;
}
ptrFrameData[aSize] = 0;
oscl_strncpy(aID3MetaData.iTrackNumber.pChar, (char*)ptrFrameData, MAX_UNICODE_BUF_LEN_TRACK_NUMBER);
aID3MetaData.iTrackNumber.pChar[MAX_UNICODE_BUF_LEN_TRACK_NUMBER-1] = 0;
aID3MetaData.iTrackNumber.iFormat = TAudioMetaData::EISO88591_CHAR;
}
break;
case ETLEN:
{
// Handle TLEN frame
// The TLEN frame contains data referring to the recording time.
if (readByteData(iFilePtr, aSize, ptrFrameData) == false)
{
OSCL_ARRAY_DELETE(ptrFrameData);
return;
}
ptrFrameData[aSize] = 0;
// The ID3 Track Length is a numeric string in milliseconds.
uint32 temp32Low = 0;
uint32 temp32High = 0;
int32 numericStringLen = oscl_strlen((const char*)ptrFrameData);
int32 i;
if (numericStringLen > 4)
{
for (i = 0; i < 4; i++)
{
temp32Low |= ptrFrameData[numericStringLen-4+i] << (24 - (i * 8));
}
for (i = 0; i < (numericStringLen - 4); i++)
{
temp32High |= ptrFrameData[i] << (((numericStringLen - 5) * 8) - (i * 8));
}
}
else
{
for (i = 0; i < numericStringLen; i++)
{
temp32Low |= ptrFrameData[i] <<
(((numericStringLen - 1) * 8) - (i * 8));
}
}
// The next 3 lines is equivalent to: aID3MetaData.iTrackLength = (temp32High << 32) | temp32Low;
// It is written thus because the behavior of "temp32High << 32" (where temp32High has a width <= 32)
// is undefined in some processors.
aID3MetaData.iTrackLength = temp32High;
aID3MetaData.iTrackLength <<= 32;
aID3MetaData.iTrackLength += temp32Low;
// Go from milliseconds to microseconds.
aID3MetaData.iTrackLength *= 1000;
}
break;
case ETYER:
{
// Handle TYER frame
// The TYER frame contains data referring to the year.
if (readByteData(iFilePtr, aSize, ptrFrameData) == false)
{
OSCL_ARRAY_DELETE(ptrFrameData);
return;
}
ptrFrameData[aSize] = 0;
oscl_strncpy(aID3MetaData.iYear.pChar, (char*)ptrFrameData, MAX_UNICODE_BUF_LEN_YEAR);
aID3MetaData.iYear.pChar[MAX_UNICODE_BUF_LEN_YEAR-1] = 0;
aID3MetaData.iYear.iFormat = TAudioMetaData::EISO88591_CHAR;
}
break;
case ECOMT:
{
// Handle COMM frame
// The COMM frame contains data referring to comments
if (readByteData(iFilePtr, aSize, ptrFrameData) == false)
{
OSCL_ARRAY_DELETE(ptrFrameData);
return;
}
ptrFrameData[aSize] = 0;
char* strptr = (char*)ptrFrameData;
oscl_memset(aID3MetaData.iComment.langcode_pChar, 0, MAX_UNICODE_BUF_LEN_COMMENT_LANGCODE);
oscl_memset(aID3MetaData.iComment.description_pChar, 0, MAX_UNICODE_BUF_LEN_COMMENT_DESCRIPTION);
// Copy language code
oscl_strncpy(aID3MetaData.iComment.langcode_pChar, strptr, MAX_UNICODE_BUF_LEN_COMMENT_LANGCODE);
aID3MetaData.iComment.langcode_pChar[MAX_UNICODE_BUF_LEN_COMMENT_LANGCODE-1] = 0;
// Move the string pointer past the language code
strptr += 3;
// Copy comment description string
uint32 commentstrlen = oscl_strlen(strptr);
if (commentstrlen < (aSize - 5))
{
oscl_strncpy(aID3MetaData.iComment.description_pChar, strptr, MAX_UNICODE_BUF_LEN_COMMENT_DESCRIPTION);
aID3MetaData.iComment.description_pChar[MAX_UNICODE_BUF_LEN_COMMENT_DESCRIPTION-1] = 0;
strptr += (commentstrlen + 1);
}
// Finally copy the comment string
oscl_strncpy(aID3MetaData.iComment.pChar, strptr, MAX_UNICODE_BUF_LEN_COMMENT);
aID3MetaData.iComment.pChar[MAX_UNICODE_BUF_LEN_COMMENT-1] = 0;
aID3MetaData.iComment.iFormat = TAudioMetaData::EISO88591_CHAR;
}
break;
default:
{
// Frame is not yet supported
break;
}
}
OSCL_ARRAY_DELETE(ptrFrameData);
ptrFrameData = NULL;
}
//----------------------------------------------------------------------------
// FUNCTION NAME: CID3TagParser::HandleID3V2FrameDataUnicode16(
// TFrameTypeID3V2 aFrameType,
// uint32 aPos,
// uint32 aSize,
// uint32 aEndianType,
// TAudioMetaData& aID3MetaData)
//----------------------------------------------------------------------------
// INPUT AND OUTPUT DEFINITIONS
//
// Inputs:
// aFrameType - enumerated TFrameTypeID3V2 type - used to determine if
// Frame is supported
// aPos - position in file where frame data begins
// aSize - size of the frame data
// aEndianType - flag indicator regarding the text endian type
// aID3MetaData - pointer to repository for parsed data
//
// Outputs:
// aID3MetaData - pointer to repository for parsed data
//
// Returns: None
//
// Global Variables Used: None
//
//----------------------------------------------------------------------------
// FUNCTION DESCRIPTION
//
// This function receives a ID3V2 frame and handles it accordingly. Each
// frame header is composed of 10 bytes - 4 bytes for FrameID, 4 bytes for
// FrameSize, and 2 bytes for FrameFlags, respectively. Once we have a
// frame's unique FrameID, we can handle the frame accordingly. (eg. The
// frame with FrameID = "TIT2" contains data describing the title.
// Clearly, the data in that frame should be copied to it respective
// location in aID3MetaData. The location for the data with FrameID = "TIT2"
// goes in the aID3MetaData.iTitle buffer. This line of code accomplishes our
// objective: aID3MetaData.iTitle.Copy(ptrFrameData16); All of the frames
// sent to this function have unicode strings in them that will need to be
// read different than the ASCII strings.
//
//------------------------------------------------------------------------------
void CID3TagParser::HandleID3V2FrameDataUnicode16(TID3V2FrameType aFrameType,
uint32 aPos,
uint32 aSize,
uint32 aEndianType,
TAudioMetaData& aID3MetaData)
{
// seek to the beginning of the current frame data
if (iFilePtr->Seek(aPos, Oscl_File::SEEKSET) == -1)
{
return;
}
// create buffers to store frame data
uint8* frameData = OSCL_ARRAY_NEW(uint8, aSize + 2);
if (frameData == NULL)
{
return;
}
oscl_wchar* frameDataWC = OSCL_ARRAY_NEW(oscl_wchar, aSize + 2);
if (frameDataWC == NULL)
{
OSCL_ARRAY_DELETE(frameData);
return;
}
uint8* ptrFrameData = frameData;
oscl_wchar* ptrFrameDataWC = frameDataWC;
oscl_memset(frameData, 0, aSize + 2);
oscl_memset(frameDataWC, 0, sizeof(oscl_wchar)*(aSize + 1));
switch (aFrameType)
{
case ETIT2:
{ // Handle TIT2 frame
// The TIT2 frame contains data referring to the title.
if (readByteData(iFilePtr, aSize, ptrFrameData) == false)
{
OSCL_ARRAY_DELETE(frameData);
OSCL_ARRAY_DELETE(frameDataWC);
return;
}
ptrFrameData[aSize] = 0;
ptrFrameData[aSize+1] = 0;
EightBitToWideCharBufferTransfer(ptrFrameData,
aSize,
aEndianType,
ptrFrameDataWC);
oscl_strncpy(aID3MetaData.iTitle.pWChar, ptrFrameDataWC, MAX_UNICODE_BUF_LEN_TITLE);
aID3MetaData.iTitle.pWChar[MAX_UNICODE_BUF_LEN_TITLE-1] = NULL_TERM_CHAR;
if (aEndianType == UNICODE_BIG_ENDIAN)
{
aID3MetaData.iTitle.iFormat = TAudioMetaData::EUTF16BE_WCHAR;
}
else
{
aID3MetaData.iTitle.iFormat = TAudioMetaData::EUTF16_WCHAR;
}
iTitleFoundFlag = true;
}
break;
case ETPE1:
{
// Handle TPE1 frame
// The TPE1 frame contains data referring to the artist.
if (readByteData(iFilePtr, aSize, ptrFrameData) == false)
{
OSCL_ARRAY_DELETE(frameData);
OSCL_ARRAY_DELETE(frameDataWC);
return;
}
ptrFrameData[aSize] = 0;
EightBitToWideCharBufferTransfer(ptrFrameData,
aSize,
aEndianType,
ptrFrameDataWC);
oscl_strncpy(aID3MetaData.iArtist.pWChar, ptrFrameDataWC, MAX_UNICODE_BUF_LEN_ARTIST);
aID3MetaData.iArtist.pWChar[MAX_UNICODE_BUF_LEN_ARTIST-1] = NULL_TERM_CHAR;
if (aEndianType == UNICODE_BIG_ENDIAN)
{
aID3MetaData.iArtist.iFormat = TAudioMetaData::EUTF16BE_WCHAR;
}
else
{
aID3MetaData.iArtist.iFormat = TAudioMetaData::EUTF16_WCHAR;
}
}
break;
case ETPOS:
{
// Handle TPOS/TPA frame
// The TPOS frame contains data defining if this is part of
// a multi disc set.
if (readByteData(iFilePtr, aSize, ptrFrameData) == false)
{
OSCL_ARRAY_DELETE(frameData);
OSCL_ARRAY_DELETE(frameDataWC);
return;
}
ptrFrameData[aSize] = 0;
EightBitToWideCharBufferTransfer(ptrFrameData,
aSize,
aEndianType,
ptrFrameDataWC);
oscl_strncpy(aID3MetaData.iSet.pWChar, ptrFrameDataWC, MAX_UNICODE_BUF_LEN_SET);
aID3MetaData.iSet.pWChar[MAX_UNICODE_BUF_LEN_SET-1] = NULL_TERM_CHAR;
if (aEndianType == UNICODE_BIG_ENDIAN)
{
aID3MetaData.iSet.iFormat = TAudioMetaData::EUTF16BE_WCHAR;
}
else
{
aID3MetaData.iSet.iFormat = TAudioMetaData::EUTF16_WCHAR;
}
}
break;
case ETALB:
{
// Handle TALB frame
// The TALB frame contains data referring to the album.
if (readByteData(iFilePtr, aSize, ptrFrameData) == false)
{
OSCL_ARRAY_DELETE(frameData);
OSCL_ARRAY_DELETE(frameDataWC);
return;
}
ptrFrameData[aSize] = 0;
EightBitToWideCharBufferTransfer(ptrFrameData,
aSize,
aEndianType,
ptrFrameDataWC);
oscl_strncpy(aID3MetaData.iAlbum.pWChar, ptrFrameDataWC, MAX_UNICODE_BUF_LEN_ALBUM);
aID3MetaData.iAlbum.pWChar[MAX_UNICODE_BUF_LEN_ALBUM-1] = NULL_TERM_CHAR;
if (aEndianType == UNICODE_BIG_ENDIAN)
{
aID3MetaData.iAlbum.iFormat = TAudioMetaData::EUTF16BE_WCHAR;
}
else
{
aID3MetaData.iAlbum.iFormat = TAudioMetaData::EUTF16_WCHAR;
}
}
break;
case ETCOP:
{
// Handle TCOP frame
// The TCOP frame contains data referring to the copyright.
if (readByteData(iFilePtr, aSize, ptrFrameData) == false)
{
OSCL_ARRAY_DELETE(frameData);
OSCL_ARRAY_DELETE(frameDataWC);
return;
}
ptrFrameData[aSize] = 0;
EightBitToWideCharBufferTransfer(ptrFrameData,
aSize,
aEndianType,
ptrFrameDataWC);
oscl_strncpy(aID3MetaData.iCopyright.pWChar, ptrFrameDataWC, MAX_UNICODE_BUF_LEN_COPYRIGHT);
aID3MetaData.iCopyright.pWChar[MAX_UNICODE_BUF_LEN_COPYRIGHT-1] = NULL_TERM_CHAR;
if (aEndianType == UNICODE_BIG_ENDIAN)
{
aID3MetaData.iCopyright.iFormat = TAudioMetaData::EUTF16BE_WCHAR;
}
else
{
aID3MetaData.iCopyright.iFormat = TAudioMetaData::EUTF16_WCHAR;
}
}
break;
case ETCON:
{
// Handle TCON frame
// The TCON frame contains data referring to the genre.
if (readByteData(iFilePtr, aSize, ptrFrameData) == false)
{
OSCL_ARRAY_DELETE(frameData);
OSCL_ARRAY_DELETE(frameDataWC);
return;
}
ptrFrameData[aSize] = 0;
EightBitToWideCharBufferTransfer(ptrFrameData,
aSize,
aEndianType,
ptrFrameDataWC);
oscl_strncpy(aID3MetaData.iGenre.pWChar, ptrFrameDataWC, MAX_UNICODE_BUF_LEN_GENRE);
aID3MetaData.iGenre.pWChar[MAX_UNICODE_BUF_LEN_GENRE-1] = NULL_TERM_CHAR;
if (aEndianType == UNICODE_BIG_ENDIAN)
{
aID3MetaData.iGenre.iFormat = TAudioMetaData::EUTF16BE_WCHAR;
}
else
{
aID3MetaData.iGenre.iFormat = TAudioMetaData::EUTF16_WCHAR;
}
}
break;
case ETRCK:
{
// Handle TRCK frame
// The TRCK frame contains data referring to the track number.
if (readByteData(iFilePtr, aSize, ptrFrameData) == false)
{
OSCL_ARRAY_DELETE(frameData);
OSCL_ARRAY_DELETE(frameDataWC);
return;
}
ptrFrameData[aSize] = 0;
EightBitToWideCharBufferTransfer(ptrFrameData,
aSize,
aEndianType,
ptrFrameDataWC);
oscl_strncpy(aID3MetaData.iTrackNumber.pWChar, ptrFrameDataWC, MAX_UNICODE_BUF_LEN_TRACK_NUMBER);
aID3MetaData.iTrackNumber.pWChar[MAX_UNICODE_BUF_LEN_TRACK_NUMBER-1] = NULL_TERM_CHAR;
if (aEndianType == UNICODE_BIG_ENDIAN)
{
aID3MetaData.iTrackNumber.iFormat = TAudioMetaData::EUTF16BE_WCHAR;
}
else
{
aID3MetaData.iTrackNumber.iFormat = TAudioMetaData::EUTF16_WCHAR;
}
}
break;
case ETYER:
{
// Handle TYER frame
// The TYER frame contains data referring to the year.
if (readByteData(iFilePtr, aSize, ptrFrameData) == false)
{
OSCL_ARRAY_DELETE(frameData);
OSCL_ARRAY_DELETE(frameDataWC);
return;
}
ptrFrameData[aSize] = 0;
EightBitToWideCharBufferTransfer(ptrFrameData,
aSize,
aEndianType,
ptrFrameDataWC);
oscl_strncpy(aID3MetaData.iYear.pWChar, ptrFrameDataWC, MAX_UNICODE_BUF_LEN_YEAR);
aID3MetaData.iYear.pWChar[MAX_UNICODE_BUF_LEN_YEAR-1] = NULL_TERM_CHAR;
if (aEndianType == UNICODE_BIG_ENDIAN)
{
aID3MetaData.iYear.iFormat = TAudioMetaData::EUTF16BE_WCHAR;
}
else
{
aID3MetaData.iYear.iFormat = TAudioMetaData::EUTF16_WCHAR;
}
}
break;
case ECOMT:
{
// Handle COMM frame
// The COMM frame contains data referring to comments
if (readByteData(iFilePtr, aSize, ptrFrameData) == false)
{
OSCL_ARRAY_DELETE(frameData);
OSCL_ARRAY_DELETE(frameDataWC);
return;
}
ptrFrameData[aSize] = 0;
EightBitToWideCharBufferTransfer(ptrFrameData,
aSize,
aEndianType,
ptrFrameDataWC);
oscl_wchar* wstrptr = ptrFrameDataWC;
oscl_memset(aID3MetaData.iComment.langcode_pWChar, 0, MAX_UNICODE_BUF_LEN_COMMENT_LANGCODE);
oscl_memset(aID3MetaData.iComment.description_pWChar, 0, MAX_UNICODE_BUF_LEN_COMMENT_DESCRIPTION);
// Check for language code
oscl_strncpy(aID3MetaData.iComment.langcode_pWChar, wstrptr, MAX_UNICODE_BUF_LEN_COMMENT_LANGCODE);
aID3MetaData.iComment.langcode_pWChar[MAX_UNICODE_BUF_LEN_COMMENT_LANGCODE-1] = 0;
// Move the string pointer past the language code
wstrptr += 3;
// Check for comment description string
uint32 commentstrlen = oscl_strlen(wstrptr);
if (commentstrlen < (aSize - 5))
{
oscl_strncpy(aID3MetaData.iComment.description_pWChar, wstrptr, MAX_UNICODE_BUF_LEN_COMMENT_DESCRIPTION);
aID3MetaData.iComment.description_pWChar[MAX_UNICODE_BUF_LEN_COMMENT_DESCRIPTION-1] = 0;
wstrptr += (commentstrlen + 1);
}
// Finally copy the comment string
oscl_strncpy(aID3MetaData.iComment.pWChar, wstrptr, MAX_UNICODE_BUF_LEN_COMMENT);
aID3MetaData.iComment.pWChar[MAX_UNICODE_BUF_LEN_COMMENT-1] = NULL_TERM_CHAR;
if (aEndianType == UNICODE_BIG_ENDIAN)
{
aID3MetaData.iComment.iFormat = TAudioMetaData::EUTF16BE_WCHAR;
}
else
{
aID3MetaData.iComment.iFormat = TAudioMetaData::EUTF16_WCHAR;
}
}
break;
default:
{
// Frame is not yet supported
break;
}
}
OSCL_ARRAY_DELETE(ptrFrameData);
ptrFrameData = NULL;
OSCL_ARRAY_DELETE(ptrFrameDataWC);
ptrFrameDataWC = NULL;
}
//----------------------------------------------------------------------------
// FUNCTION NAME: CID3TagParser::HandleID3V2FrameDataUTF16(
// TFrameTypeID3V2 aFrameType,
// uint32 aPos,
// uint32 aSize,
// uint32 aEndianType,
// TAudioMetaData& aID3MetaData)
//----------------------------------------------------------------------------
// INPUT AND OUTPUT DEFINITIONS
//
// Inputs:
// aFrameType - enumerated TFrameTypeID3V2 type - used to determine if
// Frame is supported
// aPos - position in file where frame data begins
// aSize - size of the frame data
// aTextType - flag indicator regarding the text type
// aID3MetaData - pointer to repository for parsed data
//
// Outputs:
// aID3MetaData - pointer to repository for parsed data
//
// Returns: None
//
// Global Variables Used: None
//
//----------------------------------------------------------------------------
// FUNCTION DESCRIPTION
//
// This function receives a ID3V2 frame and handles it accordingly. Each
// frame header is composed of 10 bytes - 4 bytes for FrameID, 4 bytes for
// FrameSize, and 2 bytes for FrameFlags, respectively. Once we have a
// frame's unique FrameID, we can handle the frame accordingly. (eg. The
// frame with FrameID = "TIT2" contains data describing the title.
// Clearly, the data in that frame should be copied to it respective
// location in aID3MetaData. The location for the data with FrameID = "TIT2"
// goes in the aID3MetaData.iTitle buffer. This line of code accomplishes our
// objective: aID3MetaData.iTitle.Copy(ptrFrameData16); All of the frames
// sent to this function have unicode strings in them that will need to be
// read different than the ASCII strings.
//
//------------------------------------------------------------------------------
void CID3TagParser::HandleID3V2FrameDataUTF16(TID3V2FrameType aFrameType,
uint32 aPos,
uint32 aSize,
TTextType aTextType,
TAudioMetaData& aID3MetaData)
{
// seek to the beginning of the current frame data
if (iFilePtr->Seek(aPos, Oscl_File::SEEKSET) == -1)
{
return;
}
// create buffers to store frame data
uint8* frameData = OSCL_ARRAY_NEW(uint8, aSize + 2);
if (frameData == NULL)
{
return;
}
uint8* ptrFrameData = frameData;
oscl_memset(frameData, 0, aSize + 2);
switch (aFrameType)
{
case ETIT2:
{ // Handle TIT2 frame
// The TIT2 frame contains data referring to the title.
if (readByteData(iFilePtr, aSize, ptrFrameData) == false)
{
OSCL_ARRAY_DELETE(frameData);
return;
}
ptrFrameData[aSize] = 0;
ptrFrameData[aSize+1] = 0;
oscl_strncpy(aID3MetaData.iTitle.pWChar, (oscl_wchar*)ptrFrameData, MAX_UNICODE_BUF_LEN_TITLE);
aID3MetaData.iTitle.pWChar[MAX_UNICODE_BUF_LEN_TITLE-1] = NULL_TERM_CHAR;
if (aTextType == EUTF16BE)
{
aID3MetaData.iTitle.iFormat = TAudioMetaData::EUTF16BE_WCHAR;
}
else
{
aID3MetaData.iTitle.iFormat = TAudioMetaData::EUTF16_WCHAR;
}
iTitleFoundFlag = true;
}
break;
case ETPE1:
{
// Handle TPE1 frame
// The TPE1 frame contains data referring to the artist.
if (readByteData(iFilePtr, aSize, ptrFrameData) == false)
{
OSCL_ARRAY_DELETE(frameData);
return;
}
ptrFrameData[aSize] = 0;
ptrFrameData[aSize+1] = 0;
oscl_strncpy(aID3MetaData.iArtist.pWChar, (oscl_wchar*)ptrFrameData, MAX_UNICODE_BUF_LEN_ARTIST);
aID3MetaData.iArtist.pWChar[MAX_UNICODE_BUF_LEN_ARTIST-1] = NULL_TERM_CHAR;
if (aTextType == EUTF16BE)
{
aID3MetaData.iArtist.iFormat = TAudioMetaData::EUTF16BE_WCHAR;
}
else
{
aID3MetaData.iArtist.iFormat = TAudioMetaData::EUTF16_WCHAR;
}
}
break;
case ETPOS:
{
// Handle TPOS/TPA frame
// The TPOS frame contains data defining if this is part of
// a multi disc set.
if (readByteData(iFilePtr, aSize, ptrFrameData) == false)
{
OSCL_ARRAY_DELETE(frameData);
return;
}
ptrFrameData[aSize] = 0;
ptrFrameData[aSize+1] = 0;
oscl_strncpy(aID3MetaData.iSet.pWChar, (oscl_wchar*)ptrFrameData, MAX_UNICODE_BUF_LEN_SET);
aID3MetaData.iSet.pWChar[MAX_UNICODE_BUF_LEN_SET-1] = NULL_TERM_CHAR;
if (aTextType == EUTF16BE)
{
aID3MetaData.iSet.iFormat = TAudioMetaData::EUTF16BE_WCHAR;
}
else
{
aID3MetaData.iSet.iFormat = TAudioMetaData::EUTF16_WCHAR;
}
}
break;
case ETALB:
{
// Handle TALB frame
// The TALB frame contains data referring to the album.
if (readByteData(iFilePtr, aSize, ptrFrameData) == false)
{
OSCL_ARRAY_DELETE(frameData);
return;
}
ptrFrameData[aSize] = 0;
ptrFrameData[aSize+1] = 0;
oscl_strncpy(aID3MetaData.iAlbum.pWChar, (oscl_wchar*)ptrFrameData, MAX_UNICODE_BUF_LEN_ALBUM);
aID3MetaData.iAlbum.pWChar[MAX_UNICODE_BUF_LEN_ALBUM-1] = NULL_TERM_CHAR;
if (aTextType == EUTF16BE)
{
aID3MetaData.iAlbum.iFormat = TAudioMetaData::EUTF16BE_WCHAR;
}
else
{
aID3MetaData.iAlbum.iFormat = TAudioMetaData::EUTF16_WCHAR;
}
}
break;
case ETCOP:
{
// Handle TCOP frame
// The TCOP frame contains data referring to the copyright.
if (readByteData(iFilePtr, aSize, ptrFrameData) == false)
{
OSCL_ARRAY_DELETE(frameData);
return;
}
ptrFrameData[aSize] = 0;
ptrFrameData[aSize+1] = 0;
oscl_strncpy(aID3MetaData.iCopyright.pWChar, (oscl_wchar*)ptrFrameData, MAX_UNICODE_BUF_LEN_COPYRIGHT);
aID3MetaData.iCopyright.pWChar[MAX_UNICODE_BUF_LEN_COPYRIGHT-1] = NULL_TERM_CHAR;
if (aTextType == EUTF16BE)
{
aID3MetaData.iCopyright.iFormat = TAudioMetaData::EUTF16BE_WCHAR;
}
else
{
aID3MetaData.iCopyright.iFormat = TAudioMetaData::EUTF16_WCHAR;
}
}
break;
case ETCON:
{
// Handle TCON frame
// The TCON frame contains data referring to the genre.
if (readByteData(iFilePtr, aSize, ptrFrameData) == false)
{
OSCL_ARRAY_DELETE(frameData);
return;
}
ptrFrameData[aSize] = 0;
ptrFrameData[aSize+1] = 0;
oscl_strncpy(aID3MetaData.iGenre.pWChar, (oscl_wchar*)ptrFrameData, MAX_UNICODE_BUF_LEN_GENRE);
aID3MetaData.iGenre.pWChar[MAX_UNICODE_BUF_LEN_GENRE-1] = NULL_TERM_CHAR;
if (aTextType == EUTF16BE)
{
aID3MetaData.iGenre.iFormat = TAudioMetaData::EUTF16BE_WCHAR;
}
else
{
aID3MetaData.iGenre.iFormat = TAudioMetaData::EUTF16_WCHAR;
}
}
break;
case ETRCK:
{
// Handle TRCK frame
// The TRCK frame contains data referring to the track number.
if (readByteData(iFilePtr, aSize, ptrFrameData) == false)
{
OSCL_ARRAY_DELETE(frameData);
return;
}
ptrFrameData[aSize] = 0;
ptrFrameData[aSize+1] = 0;
oscl_strncpy(aID3MetaData.iTrackNumber.pWChar, (oscl_wchar*)ptrFrameData, MAX_UNICODE_BUF_LEN_TRACK_NUMBER);
aID3MetaData.iTrackNumber.pWChar[MAX_UNICODE_BUF_LEN_TRACK_NUMBER-1] = NULL_TERM_CHAR;
if (aTextType == EUTF16BE)
{
aID3MetaData.iTrackNumber.iFormat = TAudioMetaData::EUTF16BE_WCHAR;
}
else
{
aID3MetaData.iTrackNumber.iFormat = TAudioMetaData::EUTF16_WCHAR;
}
}
break;
case ETYER:
{
// Handle TYER frame
// The TYER frame contains data referring to the year.
if (readByteData(iFilePtr, aSize, ptrFrameData) == false)
{
OSCL_ARRAY_DELETE(frameData);
return;
}
ptrFrameData[aSize] = 0;
ptrFrameData[aSize+1] = 0;
oscl_strncpy(aID3MetaData.iYear.pWChar, (oscl_wchar*)ptrFrameData, MAX_UNICODE_BUF_LEN_YEAR);
aID3MetaData.iYear.pWChar[MAX_UNICODE_BUF_LEN_YEAR-1] = NULL_TERM_CHAR;
if (aTextType == EUTF16BE)
{
aID3MetaData.iYear.iFormat = TAudioMetaData::EUTF16BE_WCHAR;
}
else
{
aID3MetaData.iYear.iFormat = TAudioMetaData::EUTF16_WCHAR;
}
}
break;
case ECOMT:
{
// Handle COMM frame
// The COMM frame contains data referring to comments
// Since data in ptrFrameData has to be aligned one cannot read the
// whole comments frame at once, since the language code is 3 byte
// long and accessing the remaining part after that as a wide char
// will cause misalignment. So the reading is split into two part.
// Read Language Code (3 bytes)
if (readByteData(iFilePtr, 3, ptrFrameData) == false)
{
OSCL_ARRAY_DELETE(frameData);
return;
}
ptrFrameData[3] = 0;
oscl_wchar* wstrptr = (oscl_wchar*)ptrFrameData;
oscl_memset(aID3MetaData.iComment.langcode_pWChar, 0, MAX_UNICODE_BUF_LEN_COMMENT_LANGCODE);
oscl_memset(aID3MetaData.iComment.description_pWChar, 0, MAX_UNICODE_BUF_LEN_COMMENT_DESCRIPTION);
// Check for language code
// NOTE: language code is NEVER wide char - and it is always 3 bytes long
oscl_strncpy(aID3MetaData.iComment.langcode_pWChar, wstrptr, MAX_UNICODE_BUF_LEN_COMMENT_LANGCODE);
aID3MetaData.iComment.langcode_pWChar[MAX_UNICODE_BUF_LEN_COMMENT_LANGCODE-1] = 0;
// Reset the part of ptrFrameData to zero, which was used for language code
oscl_memset(ptrFrameData, 0, 3);
// Read the remaning part of the comments frame
if (readByteData(iFilePtr, aSize - 3, ptrFrameData) == false)
{
OSCL_ARRAY_DELETE(frameData);
return;
}
ptrFrameData[aSize-3] = 0;
ptrFrameData[aSize-2] = 0; // aSize-3+1
// Move the pointer to the beginning of the short content description
wstrptr = (oscl_wchar*)ptrFrameData;
// Check for short content description string
uint32 commentstrlen = oscl_strlen(wstrptr);
if (commentstrlen < (aSize - 5))
{
oscl_strncpy(aID3MetaData.iComment.description_pWChar, wstrptr, MAX_UNICODE_BUF_LEN_COMMENT_DESCRIPTION);
aID3MetaData.iComment.description_pWChar[MAX_UNICODE_BUF_LEN_COMMENT_DESCRIPTION-1] = 0;
// Move the pointer to the beginning of the actual comment text
wstrptr += (commentstrlen + 1);
}
// Finally copy the comment string
oscl_strncpy(aID3MetaData.iComment.pWChar, wstrptr, MAX_UNICODE_BUF_LEN_COMMENT);
aID3MetaData.iComment.pWChar[MAX_UNICODE_BUF_LEN_COMMENT-1] = NULL_TERM_CHAR;
if (aTextType == EUTF16BE)
{
aID3MetaData.iComment.iFormat = TAudioMetaData::EUTF16BE_WCHAR;
}
else
{
aID3MetaData.iComment.iFormat = TAudioMetaData::EUTF16_WCHAR;
}
}
break;
default:
{
// Frame is not yet supported
break;
}
}
OSCL_ARRAY_DELETE(ptrFrameData);
ptrFrameData = NULL;
}
//----------------------------------------------------------------------------
// FUNCTION NAME: CID3TagParser::HandleID3V2FrameDataUTF8(
// TFrameTypeID3V2 aFrameType,
// uint32 aPos,
// uint32 aSize,
// TAudioMetaData& aID3MetaData)
//----------------------------------------------------------------------------
// INPUT AND OUTPUT DEFINITIONS
//
// Inputs:
// aFrameType - enumerated TFrameTypeID3V2 type - used to determine if
// Frame is supported
// aPos - position in file where frame data begins
// aSize - size of the frame data
// aID3MetaData - pointer to repository for parsed data
//
// Outputs:
// aID3MetaData - pointer to repository for parsed data
//
// Returns: None
//
// Global Variables Used: None
//
//----------------------------------------------------------------------------
// FUNCTION DESCRIPTION
//
// This function receives a ID3V2 frame and handles it accordingly. Each
// frame header is composed of 10 bytes - 4 bytes for FrameID, 4 bytes for
// FrameSize, and 2 bytes for FrameFlags, respectively. Once we have a
// frame's unique FrameID, we can handle the frame accordingly. (eg. The
// frame with FrameID = "TIT2" contains data describing the title.
// Clearly, the data in that frame should be copied to it respective
// location in aID3MetaData. The location for the data with FrameID = "TIT2"
// goes in the aID3MetaData.iTitle buffer. This line of code accomplishes our
// objective: aID3MetaData.iTitle.Copy(ptrFrameData16); All of the frames
// sent to this function have UTF8 strings in them that will need to be
// read different than the ASCII strings.
//
//------------------------------------------------------------------------------
void CID3TagParser::HandleID3V2FrameDataUTF8(TID3V2FrameType aFrameType,
uint32 aPos,
uint32 aSize,
TAudioMetaData& aID3MetaData)
{
// seek to the beginning of the current frame data
if (iFilePtr->Seek(aPos, Oscl_File::SEEKSET) == -1)
{
return;
}
// create buffers to store frame data
uint8* frameData = OSCL_ARRAY_NEW(uint8, aSize + 1);
if (frameData == NULL)
{
return;
}
uint8* ptrFrameData = frameData;
oscl_memset(frameData, 0, aSize + 1);
switch (aFrameType)
{
case ETIT2:
{
// Handle TIT2 frame
// The TIT2 frame contains data referring to the title.
if (readByteData(iFilePtr, aSize, ptrFrameData) == false)
{
OSCL_ARRAY_DELETE(frameData);
return;
}
ptrFrameData[aSize] = 0;
oscl_strncpy(aID3MetaData.iTitle.pChar, (char*)ptrFrameData, MAX_UNICODE_BUF_LEN_TITLE);
aID3MetaData.iTitle.pChar[MAX_UNICODE_BUF_LEN_TITLE-1] = 0;
aID3MetaData.iTitle.iFormat = TAudioMetaData::EUTF8_CHAR;
iTitleFoundFlag = true;
}
break;
case ETPE1:
{
// Handle TPE1 frame
// The TPE1 frame contains data referring to the artist.
if (readByteData(iFilePtr, aSize, ptrFrameData) == false)
{
OSCL_ARRAY_DELETE(frameData);
return;
}
ptrFrameData[aSize] = 0;
oscl_strncpy(aID3MetaData.iArtist.pChar, (char*)ptrFrameData, MAX_UNICODE_BUF_LEN_ARTIST);
aID3MetaData.iArtist.pChar[MAX_UNICODE_BUF_LEN_ARTIST-1] = 0;
aID3MetaData.iArtist.iFormat = TAudioMetaData::EUTF8_CHAR;
}
break;
case ETPOS:
{
// Handle TPOS/TPA frame
if (readByteData(iFilePtr, aSize, ptrFrameData) == false)
{
OSCL_ARRAY_DELETE(frameData);
return;
}
ptrFrameData[aSize] = 0;
oscl_strncpy(aID3MetaData.iSet.pChar, (char*)ptrFrameData, MAX_UNICODE_BUF_LEN_SET);
aID3MetaData.iSet.pChar[MAX_UNICODE_BUF_LEN_ALBUM-1] = 0;
aID3MetaData.iSet.iFormat = TAudioMetaData::EUTF8_CHAR;
}
break;
case ETALB:
{
// Handle TALB frame
// The TALB frame contains data referring to the album.
if (readByteData(iFilePtr, aSize, ptrFrameData) == false)
{
OSCL_ARRAY_DELETE(frameData);
return;
}
ptrFrameData[aSize] = 0;
oscl_strncpy(aID3MetaData.iAlbum.pChar, (char*)ptrFrameData, MAX_UNICODE_BUF_LEN_ALBUM);
aID3MetaData.iAlbum.pChar[MAX_UNICODE_BUF_LEN_ALBUM-1] = 0;
aID3MetaData.iAlbum.iFormat = TAudioMetaData::EUTF8_CHAR;
}
break;
case ETCOP:
{
// Handle TCOP frame
// The TCOP frame contains data referring to the copyright.
if (readByteData(iFilePtr, aSize, ptrFrameData) == false)
{
OSCL_ARRAY_DELETE(frameData);
return;
}
ptrFrameData[aSize] = 0;
oscl_strncpy(aID3MetaData.iCopyright.pChar, (char*)ptrFrameData, MAX_UNICODE_BUF_LEN_COPYRIGHT);
aID3MetaData.iCopyright.pChar[MAX_UNICODE_BUF_LEN_COPYRIGHT-1] = 0;
aID3MetaData.iCopyright.iFormat = TAudioMetaData::EUTF8_CHAR;
}
break;
case ETCON:
{
// Handle TCON frame
// The TCON frame contains data referring to the genre.
if (readByteData(iFilePtr, aSize, ptrFrameData) == false)
{
OSCL_ARRAY_DELETE(frameData);
return;
}
ptrFrameData[aSize] = 0;
oscl_strncpy(aID3MetaData.iGenre.pChar, (char*)ptrFrameData, MAX_UNICODE_BUF_LEN_GENRE);
aID3MetaData.iGenre.pChar[MAX_UNICODE_BUF_LEN_GENRE-1] = 0;
aID3MetaData.iGenre.iFormat = TAudioMetaData::EUTF8_CHAR;
}
break;
case ETRCK:
{
// Handle TRCK frame
// The TRCK frame contains data referring to the track number.
if (readByteData(iFilePtr, aSize, ptrFrameData) == false)
{
OSCL_ARRAY_DELETE(frameData);
return;
}
ptrFrameData[aSize] = 0;
oscl_strncpy(aID3MetaData.iTrackNumber.pChar, (char*)ptrFrameData, MAX_UNICODE_BUF_LEN_TRACK_NUMBER);
aID3MetaData.iTrackNumber.pChar[MAX_UNICODE_BUF_LEN_TRACK_NUMBER-1] = 0;
aID3MetaData.iTrackNumber.iFormat = TAudioMetaData::EUTF8_CHAR;
}
break;
case ETYER:
{
// Handle TYER frame
// The TYER frame contains data referring to the year.
if (readByteData(iFilePtr, aSize, ptrFrameData) == false)
{
OSCL_ARRAY_DELETE(frameData);
return;
}
ptrFrameData[aSize] = 0;
oscl_strncpy(aID3MetaData.iYear.pChar, (char*)ptrFrameData, MAX_UNICODE_BUF_LEN_YEAR);
aID3MetaData.iYear.pChar[MAX_UNICODE_BUF_LEN_YEAR-1] = 0;
aID3MetaData.iYear.iFormat = TAudioMetaData::EUTF8_CHAR;
}
break;
case ECOMT:
{
// Handle COMM frame
// The COMM frame contains data referring to comments
if (readByteData(iFilePtr, aSize, ptrFrameData) == false)
{
OSCL_ARRAY_DELETE(frameData);
return;
}
ptrFrameData[aSize] = 0;
char* strptr = (char*)ptrFrameData;
oscl_memset(aID3MetaData.iComment.langcode_pChar, 0, MAX_UNICODE_BUF_LEN_COMMENT_LANGCODE);
oscl_memset(aID3MetaData.iComment.description_pChar, 0, MAX_UNICODE_BUF_LEN_COMMENT_DESCRIPTION);
// Copy the language code
oscl_strncpy(aID3MetaData.iComment.langcode_pChar, strptr, MAX_UNICODE_BUF_LEN_COMMENT_LANGCODE);
aID3MetaData.iComment.langcode_pChar[MAX_UNICODE_BUF_LEN_COMMENT_LANGCODE-1] = 0;
// Move the string pointer past the language code
strptr += 3;
// Check for comment description string
uint32 commentstrlen = oscl_strlen(strptr);
if (commentstrlen < (aSize - 5))
{
oscl_strncpy(aID3MetaData.iComment.description_pChar, strptr, MAX_UNICODE_BUF_LEN_COMMENT_DESCRIPTION);
aID3MetaData.iComment.description_pChar[MAX_UNICODE_BUF_LEN_COMMENT_DESCRIPTION-1] = 0;
strptr += (commentstrlen + 1);
}
// Finally copy the comment string
oscl_strncpy(aID3MetaData.iComment.pChar, strptr, MAX_UNICODE_BUF_LEN_COMMENT);
aID3MetaData.iComment.pChar[MAX_UNICODE_BUF_LEN_COMMENT-1] = 0;
aID3MetaData.iComment.iFormat = TAudioMetaData::EUTF8_CHAR;
}
break;
default:
{
// Frame is not yet supported
break;
}
}
OSCL_ARRAY_DELETE(ptrFrameData);
ptrFrameData = NULL;
}
//----------------------------------------------------------------------------
// FUNCTION NAME: CID3TagParser::FrameSupportedID3V2(void)
//----------------------------------------------------------------------------
// INPUT AND OUTPUT DEFINITIONS
//
// Inputs: None
//
// Outputs: None
//
// Returns:
// ID3V2FrameTypeReturnValue - The value that describes the current frame.
// of type enum TID3V2FrameType
//
// Global Variables Used:
// TID3V2FrameType - The enum table containing the supported frame types
//
//----------------------------------------------------------------------------
// FUNCTION DESCRIPTION
//
// This function detects the ID3V2FrameType and returns the enum value that
// corresponds to the current frame.
//
//------------------------------------------------------------------------------
TID3V2FrameType CID3TagParser::FrameSupportedID3V2(void)
{
uint8 endTestBuf[ID3V2_FRAME_NUM_BYTES_ID] = {0};
TID3V2FrameType ID3V2FrameTypeReturnValue;
if (oscl_memcmp(iID3TagInfo.iID3V2FrameID, KTIT2, ID3V2_FRAME_NUM_BYTES_ID) == 0)
{
ID3V2FrameTypeReturnValue = ETIT2;
iTitleFoundFlag = true;
}
else if (oscl_memcmp(iID3TagInfo.iID3V2FrameID, KTPE1, ID3V2_FRAME_NUM_BYTES_ID) == 0)
{
ID3V2FrameTypeReturnValue = ETPE1;
}
else if (oscl_memcmp(iID3TagInfo.iID3V2FrameID, KTALB, ID3V2_FRAME_NUM_BYTES_ID) == 0)
{
ID3V2FrameTypeReturnValue = ETALB;
}
else if (oscl_memcmp(iID3TagInfo.iID3V2FrameID, KTCOP, ID3V2_FRAME_NUM_BYTES_ID) == 0)
{
ID3V2FrameTypeReturnValue = ETCOP;
}
else if (oscl_memcmp(iID3TagInfo.iID3V2FrameID, KTCON, ID3V2_FRAME_NUM_BYTES_ID) == 0)
{
ID3V2FrameTypeReturnValue = ETCON;
}
else if (oscl_memcmp(iID3TagInfo.iID3V2FrameID, KTRCK, ID3V2_FRAME_NUM_BYTES_ID) == 0)
{
ID3V2FrameTypeReturnValue = ETRCK;
}
else if (oscl_memcmp(iID3TagInfo.iID3V2FrameID, KTDAT, ID3V2_FRAME_NUM_BYTES_ID) == 0)
{
ID3V2FrameTypeReturnValue = ETDAT;
}
else if (oscl_memcmp(iID3TagInfo.iID3V2FrameID, KTLEN, ID3V2_FRAME_NUM_BYTES_ID) == 0)
{
ID3V2FrameTypeReturnValue = ETLEN;
}
else if (oscl_memcmp(iID3TagInfo.iID3V2FrameID, KCOMM, ID3V2_FRAME_NUM_BYTES_ID) == 0)
{
ID3V2FrameTypeReturnValue = ECOMT;
}
else if (oscl_memcmp(iID3TagInfo.iID3V2FrameID, KTYER, ID3V2_FRAME_NUM_BYTES_ID) == 0)
{
ID3V2FrameTypeReturnValue = ETYER;
}
else if (oscl_memcmp(iID3TagInfo.iID3V2FrameID, KTDRC, ID3V2_FRAME_NUM_BYTES_ID) == 0)
{
ID3V2FrameTypeReturnValue = ETYER;
}
else if (oscl_memcmp(iID3TagInfo.iID3V2FrameID, endTestBuf, ID3V2_FRAME_NUM_BYTES_ID) == 0)
{
ID3V2FrameTypeReturnValue = EEND;
}
else
{
ID3V2FrameTypeReturnValue = EFrameNotSupported;
}
return ID3V2FrameTypeReturnValue;
}
//----------------------------------------------------------------------------
// FUNCTION NAME: CID3TagParser::FrameSupportedID3V22(void)
//----------------------------------------------------------------------------
// INPUT AND OUTPUT DEFINITIONS
//
// Inputs: None
//
// Outputs: None
//
// Returns:
// ID3V2FrameTypeReturnValue - The value that describes the current frame.
// of type enum TID3V2FrameType
//
// Global Variables Used:
// TID3V2FrameType - The enum table containing the supported frame types
//
//----------------------------------------------------------------------------
// FUNCTION DESCRIPTION
//
// This function detects the ID3V2FrameType and returns the enum value that
// corresponds to the current frame.
//
//------------------------------------------------------------------------------
TID3V2FrameType CID3TagParser::FrameSupportedID3V22(void)
{
uint8 endTestBuf[ID3V22_FRAME_NUM_BYTES_ID] = {0};
TID3V2FrameType ID3V2FrameTypeReturnValue;
if (oscl_memcmp(iID3TagInfo.iID3V2FrameID, KTT2, ID3V22_FRAME_NUM_BYTES_ID) == 0)
{
ID3V2FrameTypeReturnValue = ETIT2;
iTitleFoundFlag = true;
}
else if (oscl_memcmp(iID3TagInfo.iID3V2FrameID, KTP1, ID3V22_FRAME_NUM_BYTES_ID) == 0)
{
ID3V2FrameTypeReturnValue = ETPE1;
}
else if (oscl_memcmp(iID3TagInfo.iID3V2FrameID, KTAL, ID3V22_FRAME_NUM_BYTES_ID) == 0)
{
ID3V2FrameTypeReturnValue = ETALB;
}
else if (oscl_memcmp(iID3TagInfo.iID3V2FrameID, KTCR, ID3V22_FRAME_NUM_BYTES_ID) == 0)
{
ID3V2FrameTypeReturnValue = ETCOP;
}
else if (oscl_memcmp(iID3TagInfo.iID3V2FrameID, KTCO, ID3V22_FRAME_NUM_BYTES_ID) == 0)
{
ID3V2FrameTypeReturnValue = ETCON;
}
else if (oscl_memcmp(iID3TagInfo.iID3V2FrameID, KTRK, ID3V22_FRAME_NUM_BYTES_ID) == 0)
{
ID3V2FrameTypeReturnValue = ETRCK;
}
else if (oscl_memcmp(iID3TagInfo.iID3V2FrameID, KCOM, ID3V22_FRAME_NUM_BYTES_ID) == 0)
{
ID3V2FrameTypeReturnValue = ECOMT;
}
else if (oscl_memcmp(iID3TagInfo.iID3V2FrameID, KTYE, ID3V22_FRAME_NUM_BYTES_ID) == 0)
{
ID3V2FrameTypeReturnValue = ETYER;
}
else if (oscl_memcmp(iID3TagInfo.iID3V2FrameID, KTDA, ID3V22_FRAME_NUM_BYTES_ID) == 0)
{
ID3V2FrameTypeReturnValue = ETDAT;
}
else if (oscl_memcmp(iID3TagInfo.iID3V2FrameID, KTLE, ID3V22_FRAME_NUM_BYTES_ID) == 0)
{
ID3V2FrameTypeReturnValue = ETLEN;
}
else if (oscl_memcmp(iID3TagInfo.iID3V2FrameID, endTestBuf, ID3V22_FRAME_NUM_BYTES_ID) == 0)
{
ID3V2FrameTypeReturnValue = EEND;
}
else
{
ID3V2FrameTypeReturnValue = EFrameNotSupported;
}
return ID3V2FrameTypeReturnValue;
}
//----------------------------------------------------------------------------
// FUNCTION NAME: CID3TagParser::EightBitToWideCharBufferTransfer(
// const uint8* aPtrFrameData8,
// uint32 aSize,
// uint32 aEndianType,
// oscl_wchar* aPtrFrameData16)
//----------------------------------------------------------------------------
// INPUT AND OUTPUT DEFINITIONS
//
// Inputs:
// aPtrFrameData8 - pointer to input string format of either big
// or little endian.
// aSize - number of character elements in aPtrFrameData8
// aEndianType - This describes if the encoded Unicode text in the
// aPtrFrameData8 buffer is in big or little endian.
// aPtrFrameData16 - pointer to the output string in unicode format.
//
// Outputs:
// aPtrFrameData16 - pointer to the output string in unicode format.
//
// Returns: None
//
// Global Variables Used: None
//
//----------------------------------------------------------------------------
// FUNCTION DESCRIPTION
//
// This function takes in two buffers. One is of type uint8* and the other is
// of type oscl_wchar*. This function converts the data in the uint8* buffer and
// puts the data into the oscl_wchar* buffer. The endian is taken care of by this
// function as well.
//
//------------------------------------------------------------------------------
void CID3TagParser::EightBitToWideCharBufferTransfer(const uint8 * aPtrFrameData8,
uint32 aSize,
uint32 aEndianType,
oscl_wchar * aPtrFrameDataWCBase)
{
if (aPtrFrameData8 == NULL || aPtrFrameDataWCBase == NULL)
{
return;
}
oscl_wchar * aPtrFrameDataWC = aPtrFrameDataWCBase;
uint16 tempFrameData16;
oscl_wchar tempFrameDataWC = 0;
if (aEndianType != 0)
// Indication check of big-endian vs. little endian
{
uint32 z = 0;
for (uint32 x = 0; x < (aSize >> 1); x++)
{
z = x << 1;
uint8 tempByteOne = aPtrFrameData8[z];
uint8 tempByteTwo = aPtrFrameData8[z + 1];
if ((tempByteOne == 0) && (tempByteTwo == 0))
{
x++;
// End of string here and skip to start of next string.
*aPtrFrameDataWC++ = ((oscl_wchar) ' ');
}
else
{
tempFrameData16 = ((((uint16)(tempByteTwo << 8)) | tempByteOne));
tempFrameDataWC = tempFrameData16;
*aPtrFrameDataWC++ = tempFrameDataWC;
}
}
}
else
{
uint32 z = 0;
for (uint32 x = 0; x < (aSize >> 1); x++)
{
z = x << 1;
uint8 tempByteOne = aPtrFrameData8[z];
uint8 tempByteTwo = aPtrFrameData8[z + 1];
if ((tempByteTwo == 0) && (tempByteOne == 0))
{
x++;
// End of string here and skip to start of next string.
*aPtrFrameDataWC++ = ((oscl_wchar) ' ');
}
else
{
tempFrameData16 = ((((uint16)(tempByteOne << 8)) | tempByteTwo));
tempFrameDataWC = tempFrameData16;
*aPtrFrameDataWC++ = tempFrameDataWC;
}
}
}
return;
}