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); }
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); } }
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(); } }
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); }