void CommentsFrame::parseFields(const ByteVector &data) { if(data.size() < 5) { debug("A comment frame must contain at least 5 bytes."); return; } d->textEncoding = String::Type(data[0]); d->language = data.mid(1, 3); int byteAlign = d->textEncoding == String::Latin1 || d->textEncoding == String::UTF8 ? 1 : 2; ByteVectorList l = ByteVectorList::split(data.mid(4), textDelimiter(d->textEncoding), byteAlign, 2); if(l.size() == 2) { d->description = String(l.front(), d->textEncoding); d->text = String(l.back(), d->textEncoding); } }
void ChapterFrame::parseFields(const ByteVector &data) { unsigned int size = data.size(); if(size < 18) { debug("A CHAP frame must contain at least 18 bytes (1 byte element ID " "terminated by null and 4x4 bytes for start and end time and offset)."); return; } int pos = 0; unsigned int embPos = 0; d->elementID = readStringField(data, String::Latin1, &pos).data(String::Latin1); d->startTime = data.toUInt(pos, true); pos += 4; d->endTime = data.toUInt(pos, true); pos += 4; d->startOffset = data.toUInt(pos, true); pos += 4; d->endOffset = data.toUInt(pos, true); pos += 4; size -= pos; // Embedded frames are optional if(size < header()->size()) return; while(embPos < size - header()->size()) { Frame *frame = FrameFactory::instance()->createFrame(data.mid(pos + embPos), (d->tagHeader != 0)); if(!frame) return; // Checks to make sure that frame parsed correctly. if(frame->size() <= 0) { delete frame; return; } embPos += frame->size() + header()->size(); addEmbeddedFrame(frame); } }
void TableOfContentsFrame::parseFields(const ByteVector &data) { TagLib::uint size = data.size(); if(size < 6) { debug("A CTOC frame must contain at least 6 bytes (1 byte element ID terminated by " "null, 1 byte flags, 1 byte entry count and 1 byte child element ID terminated " "by null."); return; } int pos = 0; TagLib::uint embPos = 0; d->elementID = readStringField(data, String::Latin1, &pos).data(String::Latin1); d->isTopLevel = (data.at(pos) & 2) > 0; d->isOrdered = (data.at(pos++) & 1) > 0; TagLib::uint entryCount = data.at(pos++); for(TagLib::uint i = 0; i < entryCount; i++) { ByteVector childElementID = readStringField(data, String::Latin1, &pos).data(String::Latin1); d->childElements.append(childElementID); } size -= pos; if(size < header()->size()) return; while(embPos < size - header()->size()) { Frame *frame = FrameFactory::instance()->createFrame(data.mid(pos + embPos), d->tagHeader); if(!frame) return; // Checks to make sure that frame parsed correctly. if(frame->size() <= 0) { delete frame; return; } embPos += frame->size() + header()->size(); addEmbeddedFrame(frame); } }
ByteVector APE::Tag::render() const { ByteVector data; uint itemCount = 0; { for(Map<const String, Item>::ConstIterator it = d->itemListMap.begin(); it != d->itemListMap.end(); ++it) { data.append(it->second.render()); itemCount++; } } d->footer.setItemCount(itemCount); d->footer.setTagSize(data.size() + Footer::size()); d->footer.setHeaderPresent(true); return d->footer.renderHeader() + data + d->footer.renderFooter(); }
bool Registry::EnumRegValues(HKEY hkey) { string name; name.resize(1024); ByteVector data; data.resize(1024); int i=0; while (true) { DWORD cbName= (DWORD)name.size(); DWORD cbData= (DWORD)data.size(); DWORD type; LONG rc= RegEnumValue(hkey, i, stringptr(name), &cbName, NULL, &type, vectorptr(data), &cbData); if (rc==ERROR_NO_MORE_ITEMS) break; debug("value %s = %s\n", name.c_str(), ValueToString(type, data).c_str()); i++; } return true; }
MP4::AtomDataList MP4::Tag::parseData2(const MP4::Atom *atom, int expectedFlags, bool freeForm) { AtomDataList result; ByteVector data = d->file->readBlock(atom->length - 8); int i = 0; unsigned int pos = 0; while(pos < data.size()) { const int length = static_cast<int>(data.toUInt(pos)); if(length < 12) { debug("MP4: Too short atom"); return result; } const ByteVector name = data.mid(pos + 4, 4); const int flags = static_cast<int>(data.toUInt(pos + 8)); if(freeForm && i < 2) { if(i == 0 && name != "mean") { debug("MP4: Unexpected atom \"" + name + "\", expecting \"mean\""); return result; } else if(i == 1 && name != "name") { debug("MP4: Unexpected atom \"" + name + "\", expecting \"name\""); return result; } result.append(AtomData(AtomDataType(flags), data.mid(pos + 12, length - 12))); } else { if(name != "data") { debug("MP4: Unexpected atom \"" + name + "\", expecting \"data\""); return result; } if(expectedFlags == -1 || flags == expectedFlags) { result.append(AtomData(AtomDataType(flags), data.mid(pos + 16, length - 16))); } } pos += length; i++; } return result; }
void ID3v2::Tag::read() { if(!d->file) return; if(!d->file->isOpen()) return; d->file->seek(d->tagOffset); d->header.setData(d->file->readBlock(Header::size())); // If the tag size is 0, then this is an invalid tag (tags must contain at // least one frame) if(d->header.tagSize() != 0) parse(d->file->readBlock(d->header.tagSize())); // Look for duplicate ID3v2 tags and treat them as an extra blank of this one. // It leads to overwriting them with zero when saving the tag. // This is a workaround for some faulty files that have duplicate ID3v2 tags. // Unfortunately, TagLib itself may write such duplicate tags until v1.10. unsigned int extraSize = 0; while(true) { d->file->seek(d->tagOffset + d->header.completeTagSize() + extraSize); const ByteVector data = d->file->readBlock(Header::size()); if(data.size() < Header::size() || !data.startsWith(Header::fileIdentifier())) break; extraSize += Header(data).completeTagSize(); } if(extraSize != 0) { debug("ID3v2::Tag::read() - Duplicate ID3v2 tags found."); d->header.setTagSize(d->header.tagSize() + extraSize); } }
// ------------------------------------------------------------------------------------------------- void DataPlot::mousePressEvent(QMouseEvent* evt) { if (evt->button() == Qt::LeftButton || evt->button() == Qt::RightButton) { ByteVector data = m_dataView->m_currentData.bytes(); // check if there is data displayed if (data.size() <= 0) { return; } double leftDistance = evt->x() - getLeftBegin(); // user clicked in the label area if (leftDistance < 0) { return; } // check if the user clicked too much right if (evt->x() > static_cast<int>(m_xPositions.last())) { return; } double possibleSamplesPerScreen = static_cast<double>(width()) / (DEFAULT_POINTS_PER_SAMPLE * m_zoomFactor); int sample = qRound(leftDistance * possibleSamplesPerScreen / width() + getStartIndex()); if (evt->button() == Qt::LeftButton) { setLeftMarker(sample); } else { setRightMarker(sample); } } }
//============================================================================== void CC_UnitDriver::read_xdata_memory(uint16_t address, size_t count, ByteVector &data) { log_info("programmer, read xdata memory at %04Xh, count: %u", address, count); uint8_t header[] = { 0x40, 0x55, 0x00, 0x72, 0x56, 0xE5, 0x92, 0xBE, 0x57, 0x75, 0x92, 0x00, 0x74, 0x56, 0xE5, 0x83, 0x76, 0x56, 0xE5, 0x82 }; uint8_t footer[] = { 0xD4, 0x57, 0x90, 0xC2, 0x57, 0x75, 0x92, 0x90, 0x56, 0x74 }; uint8_t load_dtpr[] = { 0xBE, 0x57, 0x90, 0x00, 0x00 }; uint8_t mov_a_dtpr[] = { 0x4E, 0x55, 0xE0 }; uint8_t inc_dtpr[] = { 0x5E, 0x55, 0xA3 }; ByteVector command; vector_append(command, header, sizeof(header)); load_dtpr[sizeof(load_dtpr) - 1] = address; load_dtpr[sizeof(load_dtpr) - 2] = address >> 8; vector_append(command, load_dtpr, sizeof(load_dtpr)); for (size_t i = 0; i < count; i++) { if (i == (count - 1) || !((i + 1) % 64)) mov_a_dtpr[0] |= 1; else mov_a_dtpr[0] &= ~1; vector_append(command, mov_a_dtpr, sizeof(mov_a_dtpr)); vector_append(command, inc_dtpr, sizeof(inc_dtpr)); } vector_append(command, footer, sizeof(footer)); data.resize(count); usb_device_.bulk_write(endpoint_out_, command.size(), &command[0]); usb_device_.bulk_read(endpoint_in_, count, &data[0]); log_info("programmer, read xdata memory, data: %s", binary_to_hex(&data[0], count, " ").c_str()); }
bool FileStream::writeBlock(const ByteVector &data) { if(!isOpen()) { debug("FileStream::writeBlock() -- invalid file."); return false; } if(readOnly()) { debug("FileStream::writeBlock() -- read only file."); return false; } size_t nbBytes = writeFile(d->file, data); if (nbBytes != data.size()) { debug("FileStream::writeBlock() error, 0 bytes written."); return false; } return true; }
void APE::Item::parse(const ByteVector &data) { // 11 bytes is the minimum size for an APE item if(data.size() < 11) { debug("APE::Item::parse() -- no data in item"); return; } uint valueLength = data.mid(0, 4).toUInt(false); uint flags = data.mid(4, 4).toUInt(false); d->key = String(data.mid(8), String::UTF8); d->value = data.mid(8 + d->key.size() + 1, valueLength); setReadOnly(flags & 1); setType(ItemTypes((flags >> 1) & 3)); if(Text == d->type) d->text = StringList(ByteVectorList::split(d->value, '\0'), String::UTF8); }
long MPEG::File::nextFrameOffset(long position) { ByteVector frameSyncBytes(2, '\0'); while(true) { seek(position); const ByteVector buffer = readBlock(bufferSize()); if(buffer.isEmpty()) return -1; for(unsigned int i = 0; i < buffer.size(); ++i) { frameSyncBytes[0] = frameSyncBytes[1]; frameSyncBytes[1] = buffer[i]; if(isFrameSync(frameSyncBytes)) { const Header header(this, position + i - 1, true); if(header.isValid()) return position + i - 1; } } position += bufferSize(); } }
void MP4::Tag::parseCovr(MP4::Atom *atom, TagLib::File *file) { MP4::CoverArtList value; ByteVector data = file->readBlock(atom->length - 8); unsigned int pos = 0; while(pos < data.size()) { int length = data.mid(pos, 4).toUInt(); ByteVector name = data.mid(pos + 4, 4); int flags = data.mid(pos + 8, 4).toUInt(); if(name != "data") { debug("MP4: Unexpected atom \"" + name + "\", expecting \"data\""); return; } if(flags == MP4::CoverArt::PNG || flags == MP4::CoverArt::JPEG) { value.append(MP4::CoverArt(MP4::CoverArt::Format(flags), data.mid(pos + 16, length - 16))); } pos += length; } if(value.size() > 0) d->items.insert(atom->name, value); }
ByteVector RIFF::Info::Tag::render() const { ByteVector data("INFO"); FieldListMap::ConstIterator it = d->fieldListMap.begin(); for(; it != d->fieldListMap.end(); ++it) { ByteVector text = TagPrivate::stringHandler->render(it->second); if(text.isEmpty()) continue; data.append(it->first); data.append(ByteVector::fromUInt(text.size() + 1, false)); data.append(text); do { data.append('\0'); } while(data.size() & 1); } if(data.size() == 4) return ByteVector(); else return data; }
ByteVectorList MP4::Tag::parseData(MP4::Atom *atom, TagLib::File *file, int expectedFlags, bool freeForm) { ByteVectorList result; ByteVector data = file->readBlock(atom->length - 8); int i = 0; unsigned int pos = 0; while(pos < data.size()) { int length = data.mid(pos, 4).toUInt(); ByteVector name = data.mid(pos + 4, 4); int flags = data.mid(pos + 8, 4).toUInt(); if(freeForm && i < 2) { if(i == 0 && name != "mean") { debug("MP4: Unexpected atom \"" + name + "\", expecting \"mean\""); return result; } else if(i == 1 && name != "name") { debug("MP4: Unexpected atom \"" + name + "\", expecting \"name\""); return result; } result.append(data.mid(pos + 12, length - 12)); } else { if(name != "data") { debug("MP4: Unexpected atom \"" + name + "\", expecting \"data\""); return result; } if(expectedFlags == -1 || flags == expectedFlags) { result.append(data.mid(pos + 16, length - 16)); } } pos += length; i++; } return result; }
long MPEG::File::previousFrameOffset(long position) { ByteVector frameSyncBytes(2, '\0'); while(position > 0) { const long bufferLength = std::min<long>(position, bufferSize()); position -= bufferLength; seek(position); const ByteVector buffer = readBlock(bufferLength); for(int i = buffer.size() - 1; i >= 0; --i) { frameSyncBytes[1] = frameSyncBytes[0]; frameSyncBytes[0] = buffer[i]; if(isFrameSync(frameSyncBytes)) { const Header header(this, position + i, true); if(header.isValid()) return position + i + header.frameLength(); } } } return -1; }
void MP4::Tag::parseCovr(MP4::Atom *atom, TagLib::File *file) { MP4::CoverArtList value; ByteVector data = file->readBlock(atom->length - 8); unsigned int pos = 0; while(pos < data.size()) { int length = data.mid(pos, 4).toUInt(); ByteVector name = data.mid(pos + 4, 4); int flags = data.mid(pos + 8, 4).toUInt(); if(name != "data") { debug("MP4: Unexpected atom \"" + name + "\", expecting \"data\""); break; } if (flags == 0) { //detect cover format when the cover format bytes are not set ByteVector picHeader = data.mid(pos+16,9); const char jpeg[] = {0xff, 0xd8, 0xff, 0xe0 }; const char jfif[] = {0x10, 0x4a, 0x46, 0x49, 0x46 }; const char png[] = {0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0x00 }; if ((memcmp(picHeader.data(), png, 9) == 0)) { flags = MP4::CoverArt::PNG; } else if ((memcmp(picHeader.data(), jpeg, 4) == 0)) { flags = MP4::CoverArt::JPEG; } else if ((memcmp(picHeader.data(), jfif, 5) == 0)) { flags = MP4::CoverArt::JPEG; } } if(flags == MP4::CoverArt::PNG || flags == MP4::CoverArt::JPEG || flags == 0) { value.append(MP4::CoverArt(MP4::CoverArt::Format(flags), data.mid(pos + 16, length - 16))); } pos += length; } if(value.size() > 0) d->items.insert(atom->name, value); }
void ByteVectorStream::insert(const ByteVector &data, long long start, size_t replace) { if(data.size() < replace) { removeBlock(start + data.size(), replace - data.size()); } else if(data.size() > replace) { const size_t sizeDiff = data.size() - replace; truncate(length() + sizeDiff); const size_t readPosition = static_cast<size_t>(start + replace); const size_t writePosition = static_cast<size_t>(start + data.size()); ::memmove( d->data.data() + writePosition, d->data.data() + readPosition, static_cast<size_t>(length() - sizeDiff - readPosition)); } seek(start); writeBlock(data); }
bool MPC::File::save() { if(readOnly()) { debug("MPC::File::save() -- File is read only."); return false; } // Possibly strip ID3v2 tag if(!d->ID3v2Header && d->ID3v2Location >= 0) { removeBlock(d->ID3v2Location, d->ID3v2Size); if(d->APELocation >= 0) d->APELocation -= d->ID3v2Size; if(d->ID3v1Location >= 0) d->ID3v1Location -= d->ID3v2Size; d->ID3v2Location = -1; d->ID3v2Size = 0; } // Update ID3v1 tag if(ID3v1Tag() && !ID3v1Tag()->isEmpty()) { // ID3v1 tag is not empty. Update the old one or create a new one. if(d->ID3v1Location >= 0) { seek(d->ID3v1Location); } else { seek(0, End); d->ID3v1Location = tell(); } writeBlock(ID3v1Tag()->render()); } else { // ID3v1 tag is empty. Remove the old one. if(d->ID3v1Location >= 0) { truncate(d->ID3v1Location); d->ID3v1Location = -1; } } // Update APE tag if(APETag() && !APETag()->isEmpty()) { // APE tag is not empty. Update the old one or create a new one. if(d->APELocation < 0) { if(d->ID3v1Location >= 0) d->APELocation = d->ID3v1Location; else d->APELocation = length(); } const ByteVector data = APETag()->render(); insert(data, d->APELocation, d->APESize); if(d->ID3v1Location >= 0) d->ID3v1Location += (static_cast<long>(data.size()) - d->APESize); d->APESize = data.size(); } else { // APE tag is empty. Remove the old one. if(d->APELocation >= 0) { removeBlock(d->APELocation, d->APESize); if(d->ID3v1Location >= 0) d->ID3v1Location -= d->APESize; d->APELocation = -1; d->APESize = 0; } } return true; }
void FileStream::insert(const ByteVector &data, ulong start, ulong replace) { if(!isOpen()) { debug("File::insert() -- invalid file."); return; } if(readOnly()) { debug("File::insert() -- read only file."); return; } if(data.size() == replace) { seek(start); writeBlock(data); return; } else if(data.size() < replace) { seek(start); writeBlock(data); removeBlock(start + data.size(), replace - data.size()); return; } // Woohoo! Faster (about 20%) than id3lib at last. I had to get hardcore // and avoid TagLib's high level API for rendering just copying parts of // the file that don't contain tag data. // // Now I'll explain the steps in this ugliness: // First, make sure that we're working with a buffer that is longer than // the *differnce* in the tag sizes. We want to avoid overwriting parts // that aren't yet in memory, so this is necessary. ulong bufferLength = bufferSize(); while(data.size() - replace > bufferLength) bufferLength += bufferSize(); // Set where to start the reading and writing. long readPosition = start + replace; long writePosition = start; ByteVector buffer = data; ByteVector aboutToOverwrite(static_cast<uint>(bufferLength)); while(true) { // Seek to the current read position and read the data that we're about // to overwrite. Appropriately increment the readPosition. seek(readPosition); const size_t bytesRead = readFile(d->file, aboutToOverwrite); aboutToOverwrite.resize(bytesRead); readPosition += bufferLength; // Check to see if we just read the last block. We need to call clear() // if we did so that the last write succeeds. if(bytesRead < bufferLength) clear(); // Seek to the write position and write our buffer. Increment the // writePosition. seek(writePosition); writeBlock(buffer); // We hit the end of the file. if(bytesRead == 0) break; writePosition += buffer.size(); // Make the current buffer the data that we read in the beginning. buffer = aboutToOverwrite; } }
bool CHttpServer::parse_request(String &method, String &uri, String &query, HeaderList &headers, String &body ) { method.clear(); uri.clear(); headers.clear(); body.clear(); size_t s = 0; ByteVector request; bool parsing_headers = true; size_t content_length = 0; for (;;) { if (!receive_request(request)) return false; size_t lim = request.size(); while (parsing_headers) { size_t e; for(e = s; e < lim && request[e] != '\r'; ++e); if (e >= lim - 1) { // Incomplete line, will read further break; } if (request[e + 1] != '\n') { if (verbose) RAWLOG_ERROR("Wrong request syntax, line should ends by '\\r\\n'"); return false; } String line(&request[s], e - s); s = e + 2; if (line.empty()) { parsing_headers = false; break; } if (uri.empty()) { // Parse start line if (!parse_startline(line, method, uri, query) || uri.empty()) return false; } else { Header hdr; if (!parse_header(line, hdr) || hdr.name.empty()) return false; headers.push_back(hdr); String low; std::transform(hdr.name.begin(), hdr.name.end(), std::back_inserter(low), &::tolower); if (low == "content-length") { content_length = ::atoi(hdr.value.c_str()); } } } if (!parsing_headers) { if (content_length == 0) return true; if (lim - s < content_length) continue; body.assign(&request[s], &request[s] + content_length); return true; } } }
ByteVector ID3v2::Tag::render(int version) const { // We need to render the "tag data" first so that we have to correct size to // render in the tag's header. The "tag data" -- everything that is included // in ID3v2::Header::tagSize() -- includes the extended header, frames and // padding, but does not include the tag's header or footer. if(version != 3 && version != 4) { debug("Unknown ID3v2 version, using ID3v2.4"); version = 4; } // TODO: Render the extended header. // Downgrade the frames that ID3v2.3 doesn't support. FrameList newFrames; newFrames.setAutoDelete(true); FrameList frameList; if(version == 4) { frameList = d->frameList; } else { downgradeFrames(&frameList, &newFrames); } // Reserve a 10-byte blank space for an ID3v2 tag header. ByteVector tagData(Header::size(), '\0'); // Loop through the frames rendering them and adding them to the tagData. for(FrameList::ConstIterator it = frameList.begin(); it != frameList.end(); it++) { (*it)->header()->setVersion(version); if((*it)->header()->frameID().size() != 4) { debug("An ID3v2 frame of unsupported or unknown type \'" + String((*it)->header()->frameID()) + "\' has been discarded"); continue; } if(!(*it)->header()->tagAlterPreservation()) { const ByteVector frameData = (*it)->render(); if(frameData.size() == Frame::headerSize((*it)->header()->version())) { debug("An empty ID3v2 frame \'" + String((*it)->header()->frameID()) + "\' has been discarded"); continue; } tagData.append(frameData); } } // Compute the amount of padding, and append that to tagData. // TODO: Should be calculated in long long in taglib2. long originalSize = d->header.tagSize(); long paddingSize = originalSize - (tagData.size() - Header::size()); if(paddingSize <= 0) { paddingSize = MinPaddingSize; } else { // Padding won't increase beyond 1% of the file size or 1MB. long threshold = d->file ? d->file->length() / 100 : 0; threshold = std::max(threshold, MinPaddingSize); threshold = std::min(threshold, MaxPaddingSize); if(paddingSize > threshold) paddingSize = MinPaddingSize; } tagData.resize(static_cast<unsigned int>(tagData.size() + paddingSize), '\0'); // Set the version and data size. d->header.setMajorVersion(version); d->header.setTagSize(tagData.size() - Header::size()); // TODO: This should eventually include d->footer->render(). const ByteVector headerData = d->header.render(); std::copy(headerData.begin(), headerData.end(), tagData.begin()); return tagData; }
void ASF::File::read() { if(!isValid()) return; ByteVector guid = readBlock(16); if(guid != headerGuid) { debug("ASF: Not an ASF file."); setValid(false); return; } d->tag = new ASF::Tag(); d->properties = new ASF::AudioProperties(); bool ok; d->headerSize = readQWORD(this, &ok); if(!ok) { setValid(false); return; } int numObjects = readDWORD(this, &ok); if(!ok) { setValid(false); return; } seek(2, Current); for(int i = 0; i < numObjects; i++) { guid = readBlock(16); if(guid.size() != 16) { setValid(false); break; } long size = (long)readQWORD(this, &ok); if(!ok) { setValid(false); break; } FilePrivate::BaseObject *obj; if(guid == filePropertiesGuid) { obj = new FilePrivate::FilePropertiesObject(); } else if(guid == streamPropertiesGuid) { obj = new FilePrivate::StreamPropertiesObject(); } else if(guid == contentDescriptionGuid) { obj = new FilePrivate::ContentDescriptionObject(); } else if(guid == extendedContentDescriptionGuid) { obj = new FilePrivate::ExtendedContentDescriptionObject(); } else if(guid == headerExtensionGuid) { obj = new FilePrivate::HeaderExtensionObject(); } else if(guid == codecListGuid) { obj = new FilePrivate::CodecListObject(); } else { if(guid == contentEncryptionGuid || guid == extendedContentEncryptionGuid || guid == advancedContentEncryptionGuid) { d->properties->setEncrypted(true); } obj = new FilePrivate::UnknownObject(guid); } obj->parse(this, size); d->objects.append(obj); } }
bool ASF::File::save() { if(readOnly()) { debug("ASF::File::save() -- File is read only."); return false; } if(!isValid()) { debug("ASF::File::save() -- Trying to save invalid file."); return false; } if(!d->contentDescriptionObject) { d->contentDescriptionObject = new FilePrivate::ContentDescriptionObject(); d->objects.append(d->contentDescriptionObject); } if(!d->extendedContentDescriptionObject) { d->extendedContentDescriptionObject = new FilePrivate::ExtendedContentDescriptionObject(); d->objects.append(d->extendedContentDescriptionObject); } if(!d->headerExtensionObject) { d->headerExtensionObject = new FilePrivate::HeaderExtensionObject(); d->objects.append(d->headerExtensionObject); } if(!d->metadataObject) { d->metadataObject = new FilePrivate::MetadataObject(); d->headerExtensionObject->objects.append(d->metadataObject); } if(!d->metadataLibraryObject) { d->metadataLibraryObject = new FilePrivate::MetadataLibraryObject(); d->headerExtensionObject->objects.append(d->metadataLibraryObject); } d->extendedContentDescriptionObject->attributeData.clear(); d->metadataObject->attributeData.clear(); d->metadataLibraryObject->attributeData.clear(); const AttributeListMap allAttributes = d->tag->attributeListMap(); for(AttributeListMap::ConstIterator it = allAttributes.begin(); it != allAttributes.end(); ++it) { const String &name = it->first; const AttributeList &attributes = it->second; bool inExtendedContentDescriptionObject = false; bool inMetadataObject = false; for(AttributeList::ConstIterator jt = attributes.begin(); jt != attributes.end(); ++jt) { const Attribute &attribute = *jt; const bool largeValue = (attribute.dataSize() > 65535); const bool guid = (attribute.type() == Attribute::GuidType); if(!inExtendedContentDescriptionObject && !guid && !largeValue && attribute.language() == 0 && attribute.stream() == 0) { d->extendedContentDescriptionObject->attributeData.append(attribute.render(name)); inExtendedContentDescriptionObject = true; } else if(!inMetadataObject && !guid && !largeValue && attribute.language() == 0 && attribute.stream() != 0) { d->metadataObject->attributeData.append(attribute.render(name, 1)); inMetadataObject = true; } else { d->metadataLibraryObject->attributeData.append(attribute.render(name, 2)); } } } ByteVector data; for(List<FilePrivate::BaseObject *>::ConstIterator it = d->objects.begin(); it != d->objects.end(); ++it) { data.append((*it)->render(this)); } seek(16); writeBlock(ByteVector::fromUInt64LE(data.size() + 30)); writeBlock(ByteVector::fromUInt32LE(d->objects.size())); writeBlock(ByteVector("\x01\x02", 2)); insert(data, 30, static_cast<size_t>(d->headerSize - 30)); d->headerSize = data.size() + 30; return true; }
ByteVector MP4::Tag::renderAtom(const ByteVector &name, const ByteVector &data) const { return ByteVector::fromUInt(data.size() + 8) + name + data; }
void ID3v2::Tag::parse(const ByteVector &origData) { ByteVector data = origData; if(d->header.unsynchronisation() && d->header.majorVersion() <= 3) data = SynchData::decode(data); uint frameDataPosition = 0; uint frameDataLength = data.size(); // check for extended header if(d->header.extendedHeader()) { if(!d->extendedHeader) d->extendedHeader = new ExtendedHeader; d->extendedHeader->setData(data); if(d->extendedHeader->size() <= data.size()) { frameDataPosition += d->extendedHeader->size(); frameDataLength -= d->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(d->header.footerPresent() && Footer::size() <= frameDataLength) frameDataLength -= 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 - Frame::headerSize(d->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(d->header.footerPresent()) debug("Padding *and* a footer found. This is not allowed by the spec."); d->paddingSize = frameDataLength - frameDataPosition; return; } Frame *frame = d->factory->createFrame(data.mid(frameDataPosition), &d->header); if(!frame) return; // Checks to make sure that frame parsed correctly. if(frame->size() <= 0) { delete frame; return; } frameDataPosition += frame->size() + Frame::headerSize(d->header.majorVersion()); addFrame(frame); } }
List<Ogg::Page *> Ogg::Page::paginate(const ByteVectorList &packets, PaginationStrategy strategy, uint streamSerialNumber, int firstPage, bool firstPacketContinued, bool lastPacketCompleted, bool containsLastPacket) { List<Page *> l; int totalSize = 0; for(ByteVectorList::ConstIterator it = packets.begin(); it != packets.end(); ++it) totalSize += (*it).size(); // Handle creation of multiple pages with appropriate pagination. if(strategy == Repaginate || totalSize + packets.size() > 255 * 255) { // SPLITSIZE must be a multiple of 255 in order to get the lacing values right // create pages of about 8KB each #define SPLITSIZE (32*255) int pageIndex = 0; for(ByteVectorList::ConstIterator it = packets.begin(); it != packets.end(); ++it) { bool continued = false; // mark very first packet? if(firstPacketContinued && it==packets.begin()) { continued = true; } // append to buf ByteVector packetBuf; packetBuf.append(*it); while(packetBuf.size() > SPLITSIZE) { // output a Page ByteVector packetForOnePage; packetForOnePage.resize(SPLITSIZE); std::copy(packetBuf.begin(), packetBuf.begin() + SPLITSIZE, packetForOnePage.begin()); ByteVectorList packetList; packetList.append(packetForOnePage); Page *p = new Page(packetList, streamSerialNumber, firstPage+pageIndex, continued, false, false); l.append(p); pageIndex++; continued = true; packetBuf = packetBuf.mid(SPLITSIZE); } ByteVectorList::ConstIterator jt = it; ++jt; bool lastPacketInList = (jt == packets.end()); // output a page for the rest (we output one packet per page, so this one should be completed) ByteVectorList packetList; packetList.append(packetBuf); bool isVeryLastPacket = false; if(containsLastPacket) { // mark the very last output page as last of stream ByteVectorList::ConstIterator jt = it; ++jt; if(jt == packets.end()) { isVeryLastPacket = true; } } Page *p = new Page(packetList, streamSerialNumber, firstPage+pageIndex, continued, lastPacketInList ? lastPacketCompleted : true, isVeryLastPacket); pageIndex++; l.append(p); } } else { Page *p = new Page(packets, streamSerialNumber, firstPage, firstPacketContinued, lastPacketCompleted, containsLastPacket); l.append(p); } return l; }
Frame *FrameFactory::createFrame(const ByteVector &origData, Header *tagHeader) const { ByteVector data = origData; uint version = tagHeader->majorVersion(); Frame::Header *header = new Frame::Header(data, version); ByteVector frameID = header->frameID(); // A quick sanity check -- make sure that the frameID is 4 uppercase Latin1 // characters. Also make sure that there is data in the frame. if(!frameID.size() == (version < 3 ? 3 : 4) || header->frameSize() <= uint(header->dataLengthIndicator() ? 4 : 0) || header->frameSize() > data.size()) { delete header; return 0; } for(ByteVector::ConstIterator it = frameID.begin(); it != frameID.end(); it++) { if( (*it < 'A' || *it > 'Z') && (*it < '1' || *it > '9') ) { delete header; return 0; } } if(version > 3 && (tagHeader->unsynchronisation() || header->unsynchronisation())) { // Data lengths are not part of the encoded data, but since they are synch-safe // integers they will be never actually encoded. ByteVector frameData = data.mid(Frame::Header::size(version), header->frameSize()); frameData = SynchData::decode(frameData); data = data.mid(0, Frame::Header::size(version)) + frameData; } // TagLib doesn't mess with encrypted frames, so just treat them // as unknown frames. #if HAVE_ZLIB == 0 if(header->compression()) { debug("Compressed frames are currently not supported."); return new UnknownFrame(data, header); } #endif if(header->encryption()) { debug("Encrypted frames are currently not supported."); return new UnknownFrame(data, header); } if(!updateFrame(header)) { header->setTagAlterPreservation(true); return new UnknownFrame(data, header); } // updateFrame() might have updated the frame ID. frameID = header->frameID(); // This is where things get necissarily nasty. Here we determine which // Frame subclass (or if none is found simply an Frame) based // on the frame ID. Since there are a lot of possibilities, that means // a lot of if blocks. // Text Identification (frames 4.2) if(frameID.startsWith("T")) { TextIdentificationFrame *f = frameID != "TXXX" ? new TextIdentificationFrame(data, header) : new UserTextIdentificationFrame(data, header); d->setTextEncoding(f); if(frameID == "TCON") updateGenre(f); return f; } // Comments (frames 4.10) if(frameID == "COMM") { CommentsFrame *f = new CommentsFrame(data, header); d->setTextEncoding(f); return f; } // Attached Picture (frames 4.14) if(frameID == "APIC") { AttachedPictureFrame *f = new AttachedPictureFrame(data, header); d->setTextEncoding(f); return f; } // ID3v2.2 Attached Picture if(frameID == "PIC") { AttachedPictureFrame *f = new AttachedPictureFrameV22(data, header); d->setTextEncoding(f); return f; } // Relative Volume Adjustment (frames 4.11) if(frameID == "RVA2") return new RelativeVolumeFrame(data, header); // Unique File Identifier (frames 4.1) if(frameID == "UFID") return new UniqueFileIdentifierFrame(data, header); // General Encapsulated Object (frames 4.15) if(frameID == "GEOB") { GeneralEncapsulatedObjectFrame *f = new GeneralEncapsulatedObjectFrame(data, header); d->setTextEncoding(f); return f; } // URL link (frames 4.3) if(frameID.startsWith("W")) { if(frameID != "WXXX") { return new UrlLinkFrame(data, header); } else { UserUrlLinkFrame *f = new UserUrlLinkFrame(data, header); d->setTextEncoding(f); return f; } } // Unsynchronized lyric/text transcription (frames 4.8) if(frameID == "USLT") { UnsynchronizedLyricsFrame *f = new UnsynchronizedLyricsFrame(data, header); if(d->useDefaultEncoding) f->setTextEncoding(d->defaultEncoding); return f; } // Popularimeter (frames 4.17) if(frameID == "POPM") return new PopularimeterFrame(data, header); // Private (frames 4.27) if(frameID == "PRIV") return new PrivateFrame(data, header); return new UnknownFrame(data, header); }
void Frame::Header::setData(const ByteVector &data, uint version) { d->version = version; switch(version) { case 0: case 1: case 2: { // ID3v2.2 if(data.size() < 3) { debug("You must at least specify a frame ID."); return; } // Set the frame ID -- the first three bytes d->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) { d->frameSize = 0; return; } d->frameSize = data.mid(3, 3).toUInt(); break; } case 3: { // ID3v2.3 if(data.size() < 4) { debug("You must at least specify a frame ID."); return; } // Set the frame ID -- the first four bytes d->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) { d->frameSize = 0; return; } // Set the size -- the frame size is the four bytes starting at byte four in // the frame header (structure 4) d->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) } { // 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) } break; } case 4: default: { // ID3v2.4 if(data.size() < 4) { debug("You must at least specify a frame ID."); return; } // Set the frame ID -- the first four bytes d->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) { d->frameSize = 0; return; } // Set the size -- the frame size is the four bytes starting at byte four in // the frame header (structure 4) d->frameSize = SynchData::toUInt(data.mid(4, 4)); #ifndef NO_ITUNES_HACKS // iTunes writes v2.4 tags with v2.3-like frame sizes if(d->frameSize > 127) { if(!isValidFrameID(data.mid(d->frameSize + 10, 4))) { unsigned int uintSize = data.mid(4, 4).toUInt(); if(isValidFrameID(data.mid(uintSize + 10, 4))) { d->frameSize = uintSize; } } } #endif { // 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) } { // 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->unsynchronisation = flags[1]; // (structure 4.1.2.n) d->dataLengthIndicator = flags[0]; // (structure 4.1.2.p) } break; } } }
bool ASF::File::save() { if(readOnly()) { debug("ASF::File::save() -- File is read only."); return false; } if(!isValid()) { debug("ASF::File::save() -- Trying to save invalid file."); return false; } if(!d->contentDescriptionObject) { d->contentDescriptionObject = new ContentDescriptionObject(); d->objects.append(d->contentDescriptionObject); } if(!d->extendedContentDescriptionObject) { d->extendedContentDescriptionObject = new ExtendedContentDescriptionObject(); d->objects.append(d->extendedContentDescriptionObject); } if(!d->headerExtensionObject) { d->headerExtensionObject = new HeaderExtensionObject(); d->objects.append(d->headerExtensionObject); } if(!d->metadataObject) { d->metadataObject = new MetadataObject(); d->headerExtensionObject->objects.append(d->metadataObject); } if(!d->metadataLibraryObject) { d->metadataLibraryObject = new MetadataLibraryObject(); d->headerExtensionObject->objects.append(d->metadataLibraryObject); } ASF::AttributeListMap::ConstIterator it = d->tag->attributeListMap().begin(); for(; it != d->tag->attributeListMap().end(); it++) { const String &name = it->first; const AttributeList &attributes = it->second; bool inExtendedContentDescriptionObject = false; bool inMetadataObject = false; for(unsigned int j = 0; j < attributes.size(); j++) { const Attribute &attribute = attributes[j]; const bool largeValue = (attribute.dataSize() > 65535); const bool guid = (attribute.type() == Attribute::GuidType); if(!inExtendedContentDescriptionObject && !guid && !largeValue && attribute.language() == 0 && attribute.stream() == 0) { d->extendedContentDescriptionObject->attributeData.append(attribute.render(name)); inExtendedContentDescriptionObject = true; } else if(!inMetadataObject && !guid && !largeValue && attribute.language() == 0 && attribute.stream() != 0) { d->metadataObject->attributeData.append(attribute.render(name, 1)); inMetadataObject = true; } else { d->metadataLibraryObject->attributeData.append(attribute.render(name, 2)); } } } ByteVector data; for(unsigned int i = 0; i < d->objects.size(); i++) { data.append(d->objects[i]->render(this)); } data = headerGuid + ByteVector::fromLongLong(data.size() + 30, false) + ByteVector::fromUInt(d->objects.size(), false) + ByteVector("\x01\x02", 2) + data; insert(data, 0, (TagLib::ulong)d->size); return true; }