SjByteVector ID3v2_Frame::fieldData(const SjByteVector &frameData) const
{
	SjUint headerSize = ID3v2_FrameHeader::size(m_header->version());

	SjUint frameDataOffset = headerSize;
	SjUint frameDataLength = size();

	if(m_header->compression() || m_header->dataLengthIndicator()) {
		frameDataLength = frameData.mid(headerSize, 4).toUInt();
		frameDataOffset += 4;
	}

	if(m_header->compression()) {
		SjByteVector data(frameDataLength);

		uLongf uLongTmp = data.size(); // normally, this should be same as frameDataLength - however, on allocation errors, this may be 0!
		::uncompress((Bytef *) data.getWriteableData(),
		             (uLongf *) &uLongTmp,
		             (Bytef *) frameData.getReadableData() + frameDataOffset,
		             size());
		return data;
	}
	else
		return frameData.mid(frameDataOffset, frameDataLength);
}
void ID3v2_PopularimeterFrame::parseFields(const SjByteVector& data)
{
	m_email.Empty();
	m_rating255 = 0;
	m_counter = 0;

	int offset, pos = 0, size = (int)data.size();
	offset = data.find(textDelimiter(SJ_LATIN1), pos);
	if( offset < pos ) {
		return;
	}

	m_email = data.mid(pos, offset - pos).toString(SJ_LATIN1);
	pos = offset + 1;

	if(pos < size)
	{
		m_rating255 = (int)(data[pos]);
		pos++;

		if(pos < size)
		{
			m_counter = data.mid(pos, 4).toUInt();
		}
	}
}
void MPEG_XingHeader::parse(const SjByteVector &data)
{
	// Check to see if a valid Xing header is available.

	if(!data.startsWith((unsigned char*)"Xing"))
	{
		return;
	}

	// If the XingHeader doesn't contain the number of frames and the total stream
	// info it's invalid.

	if(!(data[7] & 0x02))
	{
		wxLogDebug(wxT("MPEG::XingHeader::parse() -- Xing header doesn't contain the total number of frames."));
		return;
	}

	if(!(data[7] & 0x04))
	{
		wxLogDebug(wxT("MPEG::XingHeader::parse() -- Xing header doesn't contain the total stream size."));
		return;
	}

	m_frames = data.mid(8, 4).toUInt();
	m_size = data.mid(12, 4).toUInt();

	m_valid = true;
}
void ID3v2_TextIdentificationFrame::parseFields(const SjByteVector &data)
{
	// read the string data type (the first byte of the field data)

	m_textEncoding = (SjStringType)(data[0]);

	// split the byte array into chunks based on the string type (two byte delimiter
	// for unicode encodings)

	int byteAlign = m_textEncoding == SJ_LATIN1 || m_textEncoding == SJ_UTF8 ? 1 : 2;

	//ByteVectorList l = ByteVectorList::split(data.mid(1), textDelimiter(d->textEncoding), byteAlign);
	SjArrayByteVector l = data.mid(1).splitToArray(textDelimiter(m_textEncoding), byteAlign);

	m_fieldList.Empty();

	// append those split values to the list and make sure that the new string's
	// type is the same specified for this frame

	/*for(ByteVectorList::Iterator it = l.begin(); it != l.end(); it++) {
	  String s(*it, d->textEncoding);
	  d->fieldList.append(s);
	}
	*/
	int i, iCount = l.GetCount();
	for( i = 0; i < iCount; i++ )
	{
		m_fieldList.Add(l.Item(i).toString(m_textEncoding));
	}
}
void ID3v2_AttachedPictureFrame::parseFields(const SjByteVector &data)
{
	if(data.size() < 5) {
		wxLogDebug(wxT("A picture frame must contain at least 5 bytes."));
		return;
	}

	int pos = 0, offset;

	// read text encoding
	m_textEncoding = (SjStringType)(data[pos]);
	pos += 1;

	if( header()->version() <= 2 )
	{
		// read image format (3 characters), valid for ID3V2_2_1 or older
		m_mimeType = data.mid(pos, 3).toString(SJ_LATIN1);
		pos += 3;
	}
	else
	{
		// read mime type (null-terminated), valid for newer specs
		offset = data.find(textDelimiter(SJ_LATIN1), pos);

		if(offset < pos)
			return;

		m_mimeType = data.mid(pos, offset - pos).toString(SJ_LATIN1);
		pos = offset + 1;
	}

	// read type
	m_type = (ID3v2_AttachedPictureType)(data[pos]);
	pos += 1;

	// read description
	offset = data.find(textDelimiter(m_textEncoding), pos);

	if(offset < pos)
		return;

	m_description = data.mid(pos, offset - pos).toString(m_textEncoding);
	pos = offset + 1;

	// read image data
	m_data = data.mid(pos);
}
Exemple #6
0
void APE_Item::parse(const SjByteVector &data)
{
	// 11 bytes is the minimum size for an APE item
	if(data.size() < 11)
	{
		wxLogDebug(wxT("APE::Item::parse() -- no data in item"));
		return;
	}

	SjUint valueLength  = data.mid(0, 4).toUInt(false);
	SjUint flags        = data.mid(4, 4).toUInt(false);

	m_key = data.mid(8).toString(SJ_UTF8); // data.mid(8) contains more than just the string -- but SjBytevector only converts up to the first null-byte at (***)
	m_binary = data.mid(8 + m_key.size() + 1, valueLength);

	setReadOnly(flags & 1);
	setType((APE_ItemType)((flags >> 1) & 3));

	if(int(m_type) < 2)
	{
		m_stringList = m_binary.splitToStrings((unsigned char)'\0', SJ_UTF8);
	}
}
void ID3v2_CommentsFrame::parseFields(const SjByteVector &data)
{
	if(data.size() < 5) {
		wxLogDebug(wxT("A comment frame must contain at least 5 bytes."));
		return;
	}

	m_textEncoding = (SjStringType)(data[0]);
	m_language = data.mid(1, 3);

	int byteAlign = (m_textEncoding == SJ_LATIN1 || m_textEncoding == SJ_UTF8) ? 1 : 2;

	//ByteVectorList l = ByteVectorList::split(data.mid(4), textDelimiter(d->textEncoding), byteAlign, 2);
	SjArrayByteVector l = data.mid(4).splitToArray(textDelimiter(m_textEncoding), byteAlign, 2);

	if(l.GetCount() == 2) {
		/*d->description = String(l.front(), d->textEncoding);
		d->text = String(l.back(), d->textEncoding);
		*/
		m_description = l.Item(0).toString(m_textEncoding);
		m_text = l.Item(1).toString(m_textEncoding);
	}
}
Exemple #8
0
void APE_Tag::parse(const SjByteVector &data)
{
	SjUint pos = 0;

	// 11 bytes is the minimum size for an APE item
	for(SjUint i = 0; i < m_footer.itemCount() && pos <= data.size() - 11; i++)
	{
		APE_Item item;
		item.parse(data.mid(pos));

		setItem(item.key().Upper(), item);

		pos += item.size();
	}
}
Exemple #9
0
void APE_Footer::parse(const SjByteVector &data)
{
	if( data.size() < APE_FOOTER_SIZE )
	{
		return;
	}

	// The first eight bytes, data[0..7], are the File Identifier, "APETAGEX".

	// Read the version number
	m_version = data.mid(8, 4).toUInt(false);

	// Read the tag size
	m_tagSize = data.mid(12, 4).toUInt(false);

	// Read the item count
	m_itemCount = data.mid(16, 4).toUInt(false);

	// Read the flags
	unsigned long flags = (unsigned long)data.mid(20, 4).toUInt(false);
	m_headerPresent =   (flags & (1<<31))!=0;
	m_footerPresent = !((flags & (1<<30))!=0);
	m_isHeader      =   (flags & (1<<29))!=0;
}
void ID3v2_Tag::parse(const SjByteVector &data)
{
	SjUint frameDataPosition = 0;
	SjUint frameDataLength = data.size();

	// check for extended header

	if(m_header.extendedHeader()) {
		if(!m_extendedHeader)
			m_extendedHeader = new ID3v2_ExtendedHeader;
		m_extendedHeader->setData(data);
		if(m_extendedHeader->size() <= data.size()) {
			frameDataPosition += m_extendedHeader->size();
			frameDataLength -= m_extendedHeader->size();
		}
	}

	// check for footer -- we don't actually need to parse it, as it *must*
	// contain the same data as the header, but we do need to account for its
	// size.

	if(m_header.footerPresent() && ID3v2_Footer::size() <= frameDataLength)
		frameDataLength -= ID3v2_Footer::size();

	// parse frames

	// Make sure that there is at least enough room in the remaining frame data for
	// a frame header.

	while(frameDataPosition < frameDataLength - ID3v2_Frame::headerSize(m_header.majorVersion())) {

		// If the next data is position is 0, assume that we've hit the padding
		// portion of the frame data.

		if(data.at(frameDataPosition) == 0) {
			if(m_header.footerPresent())
				wxLogDebug(wxT("Padding *and* a footer found.  This is not allowed by the spec."));

			m_paddingSize = frameDataLength - frameDataPosition;
			return;
		}

		ID3v2_Frame *frame = m_factory->createFrame(data.mid(frameDataPosition),
		                     m_header.majorVersion());

		if(!frame)
			return;

		// get the next frame position

		frameDataPosition += frame->size() + ID3v2_Frame::headerSize(m_header.majorVersion());

		// add the frame if it has a size of at least 1 byte (smaller frames are not allowed
		// by the specification, but they're returned from createFrame() to allow seeking to the
		// next frame).
		// modification by me

		if(frame->size() <= 0) {
			delete frame;
		}
		else {
			addFrame(frame);
		}
	}
}
void ID3v2_FrameHeader::setFrameID(const SjByteVector &id)
{
	m_frameID = id.mid(0, 4);
}
void ID3v2_FrameHeader::setData(const SjByteVector &data, SjUint version)
{
	// this was ID3v2_FrameHeaderPrivate
	m_isOkay = FALSE;
	m_frameSize = 0;
	m_version = 4;
	m_tagAlterPreservation = false;
	m_fileAlterPreservation = false;
	m_readOnly = false;
	m_groupingIdentity = false;
	m_compression = false;
	m_encryption = false;
	m_unsyncronisation = false;
	m_dataLengthIndicator = false;
	// /ID3v2_FrameHeaderPrivate


	m_version = version;

	switch(version) {
		case 0:
		case 1:
		case 2:
		{
			// ID3v2.2

			if(data.size() < 3) {
				wxLogDebug(wxT("You must at least specify a frame ID."));
				return;
			}

			// Set the frame ID -- the first three bytes

			m_frameID = data.mid(0, 3);

			// If the full header information was not passed in, do not continue to the
			// steps to parse the frame size and flags.

			if(data.size() < 6) {
				return;
			}

			m_frameSize = data.mid(3, 3).toUInt();

			break;
		}
		case 3:
		{
			// ID3v2.3 - see http://www.id3.org/id3v2.3.0.html#sec3.3

			if(data.size() < 4) {
				wxLogDebug(wxT("You must at least specify a frame ID."));
				return;
			}

			// Set the frame ID -- the first four bytes

			m_frameID = data.mid(0, 4);

			// If the full header information was not passed in, do not continue to the
			// steps to parse the frame size and flags.

			if(data.size() < 10) {
				return;
			}

			// Set the size -- the frame size is the four bytes starting at byte four in
			// the frame header (structure 4)

			m_frameSize = data.mid(4, 4).toUInt();

			{	// read the first byte of flags
				/*std::bitset<8> flags(data[8]);
				d->tagAlterPreservation  = flags[7]; // (structure 3.3.1.a)
				d->fileAlterPreservation = flags[6]; // (structure 3.3.1.b)
				d->readOnly              = flags[5]; // (structure 3.3.1.c)*/
				unsigned char flags = data[8];
				m_tagAlterPreservation    = (flags & (1<<7)) != 0;
				m_fileAlterPreservation   = (flags & (1<<6)) != 0;
				m_readOnly                = (flags & (1<<5)) != 0;
			}

			{	// read the second byte of flags
				/*std::bitset<8> flags(data[9]);
				d->compression         = flags[7]; // (structure 3.3.1.i)
				d->encryption          = flags[6]; // (structure 3.3.1.j)
				d->groupingIdentity    = flags[5]; // (structure 3.3.1.k)*/
				unsigned char flags = data[9];
				m_compression     = (flags & (1<<7)) != 0;
				m_encryption          = (flags & (1<<6)) != 0;
				m_groupingIdentity    = (flags & (1<<5)) != 0;
			}
			break;
		}
		case 4:
		default:
		{
			// ID3v2.4

			if(data.size() < 4) {
				wxLogDebug(wxT("You must at least specify a frame ID."));
				return;
			}

			// Set the frame ID -- the first four bytes

			m_frameID = data.mid(0, 4);

			// If the full header information was not passed in, do not continue to the
			// steps to parse the frame size and flags.

			if(data.size() < 10) {
				return;
			}

			// Set the size -- the frame size is the four bytes starting at byte four in
			// the frame header (structure 4)

			m_frameSize = ID3v2_SynchDataToUInt(data.mid(4, 4));

			{	// read the first byte of flags
				/*std::bitset<8> flags(data[8]);
				d->tagAlterPreservation  = flags[6]; // (structure 4.1.1.a)
				d->fileAlterPreservation = flags[5]; // (structure 4.1.1.b)
				d->readOnly              = flags[4]; // (structure 4.1.1.c)*/
				unsigned char flags = data[8];
				m_tagAlterPreservation    = (flags & (1<<6)) != 0;
				m_fileAlterPreservation   = (flags & (1<<5)) != 0;
				m_readOnly                = (flags & (1<<4)) != 0;
			}

			{	// read the second byte of flags
				/*std::bitset<8> flags(data[9]);
				d->groupingIdentity    = flags[6]; // (structure 4.1.2.h)
				d->compression         = flags[3]; // (structure 4.1.2.k)
				d->encryption          = flags[2]; // (structure 4.1.2.m)
				d->unsyncronisation    = flags[1]; // (structure 4.1.2.n)
				d->dataLengthIndicator = flags[0]; // (structure 4.1.2.p)*/
				unsigned char flags = data[9];
				m_groupingIdentity    = (flags & (1<<6)) != 0;
				m_compression         = (flags & (1<<3)) != 0;
				m_encryption          = (flags & (1<<2)) != 0;
				m_unsyncronisation    = (flags & (1<<1)) != 0;
				m_dataLengthIndicator = (flags & (1<<0)) != 0;
			}
			break;
		}
	}

	m_isOkay = TRUE;
}
void ID3v2_CommentsFrame::setLanguage(const SjByteVector &languageEncoding)
{
	m_language = languageEncoding.mid(0, 3);
}