void MP4::Tag::parseText(const MP4::Atom *atom, int expectedFlags) { ByteVectorList data = parseData(atom, expectedFlags); if(data.size()) { StringList value; for(unsigned int i = 0; i < data.size(); i++) { value.append(String(data[i], String::UTF8)); } addItem(atom->name, value); } }
void MP4::Tag::parseText(MP4::Atom *atom, TagLib::File *file, int expectedFlags) { ByteVectorList data = parseData(atom, file, expectedFlags); if(data.size()) { StringList value; for(unsigned int i = 0; i < data.size(); i++) { value.append(String(data[i], String::UTF8)); } d->items.insert(atom->name, value); } }
void MP4::Tag::parseFreeForm(MP4::Atom *atom, TagLib::File *file) { ByteVectorList data = parseData(atom, file, 1, true); if(data.size() > 2) { StringList value; for(unsigned int i = 2; i < data.size(); i++) { value.append(String(data[i], String::UTF8)); } String name = "----:" + data[0] + ':' + data[1]; d->items.insert(name, value); } }
void UnsynchronizedLyricsFrame::parseFields(const ByteVector &data) { if(data.size() < 5) { debug("An unsynchronized lyrics 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) { if(d->textEncoding == String::Latin1) { d->description = Tag::latin1StringHandler()->parse(l.front()); d->text = Tag::latin1StringHandler()->parse(l.back()); } else { d->description = String(l.front(), d->textEncoding); d->text = String(l.back(), d->textEncoding); } } }
ByteVector MP4::Tag::renderFreeForm(const String &name, const MP4::Item &item) const { StringList header = StringList::split(name, ":"); if (header.size() != 3) { debug("MP4: Invalid free-form item name \"" + name + "\""); return ByteVector::null; } ByteVector data; data.append(renderAtom("mean", ByteVector::fromUInt(0) + header[1].data(String::UTF8))); data.append(renderAtom("name", ByteVector::fromUInt(0) + header[2].data(String::UTF8))); AtomDataType type = item.atomDataType(); if(type == TypeUndefined) { if(!item.toStringList().isEmpty()) { type = TypeUTF8; } else { type = TypeImplicit; } } if(type == TypeUTF8) { StringList value = item.toStringList(); for(unsigned int i = 0; i < value.size(); i++) { data.append(renderAtom("data", ByteVector::fromUInt(type) + ByteVector(4, '\0') + value[i].data(String::UTF8))); } } else { ByteVectorList value = item.toByteVectorList(); for(unsigned int i = 0; i < value.size(); i++) { data.append(renderAtom("data", ByteVector::fromUInt(type) + ByteVector(4, '\0') + value[i])); } } return renderAtom("----", data); }
void testSplitSingleChar_2() { ByteVector v("a"); ByteVectorList l = ByteVectorList::split(v, " "); CPPUNIT_ASSERT_EQUAL(TagLib::uint(1), l.size()); CPPUNIT_ASSERT_EQUAL(ByteVector("a"), l[0]); }
void MP4::Tag::parseByte(MP4::Atom *atom, TagLib::File *file) { ByteVectorList data = parseData(atom, file); if(data.size()) { addItem(atom->name, (uchar)data[0].at(0)); } }
void MP4::Tag::parseLongLong(MP4::Atom *atom, TagLib::File *file) { ByteVectorList data = parseData(atom, file); if(data.size()) { addItem(atom->name, data[0].toLongLong()); } }
void testSplitSingleChar_2() { ByteVector v("a"); ByteVectorList l = ByteVectorList::split(v, " "); CPPUNIT_ASSERT_EQUAL((unsigned int)1, l.size()); CPPUNIT_ASSERT_EQUAL(ByteVector("a"), l[0]); }
void MP4::Tag::parseInt(MP4::Atom *atom, TagLib::File *file) { ByteVectorList data = parseData(atom, file); if(data.size()) { d->items.insert(atom->name, (int)data[0].toShort()); } }
void MP4::Tag::parseByte(const MP4::Atom *atom) { ByteVectorList data = parseData(atom); if(data.size()) { addItem(atom->name, (uchar)data[0].at(0)); } }
void MP4::Tag::parseLongLong(const MP4::Atom *atom) { ByteVectorList data = parseData(atom); if(data.size()) { addItem(atom->name, data[0].toLongLong()); } }
void MP4::Tag::parseInt(const MP4::Atom *atom) { ByteVectorList data = parseData(atom); if(data.size()) { addItem(atom->name, (int)data[0].toShort()); } }
void MP4::Tag::parseBool(MP4::Atom *atom, TagLib::File *file) { ByteVectorList data = parseData(atom, file); if(data.size()) { bool value = data[0].size() ? data[0][0] != '\0' : false; d->items.insert(atom->name, value); } }
void MP4::Tag::parseBool(const MP4::Atom *atom) { ByteVectorList data = parseData(atom); if(data.size()) { bool value = data[0].size() ? data[0][0] != '\0' : false; addItem(atom->name, value); } }
ByteVector MP4::Tag::renderData(const ByteVector &name, int flags, const ByteVectorList &data) const { ByteVector result; for(unsigned int i = 0; i < data.size(); i++) { result.append(renderAtom("data", ByteVector::fromUInt(flags) + ByteVector(4, '\0') + data[i])); } return renderAtom(name, result); }
void MP4::Tag::parseIntPair(MP4::Atom *atom, TagLib::File *file) { ByteVectorList data = parseData(atom, file); if(data.size()) { int a = data[0].mid(2, 2).toShort(); int b = data[0].mid(4, 2).toShort(); d->items.insert(atom->name, MP4::Item(a, b)); } }
void MP4::Tag::parseIntPair(const MP4::Atom *atom) { ByteVectorList data = parseData(atom); if(data.size()) { const int a = data[0].toShort(2U); const int b = data[0].toShort(4U); addItem(atom->name, MP4::Item(a, b)); } }
void MP4::Tag::parseGnre(MP4::Atom *atom, TagLib::File *file) { ByteVectorList data = parseData(atom, file); if(data.size()) { int idx = (int)data[0].toShort(); if(!d->items.contains("\251gen") && idx > 0) { d->items.insert("\251gen", StringList(ID3v1::genre(idx - 1))); } } }
void MP4::Tag::parseGnre(const MP4::Atom *atom) { ByteVectorList data = parseData(atom); if(data.size()) { int idx = (int)data[0].toShort(); if(idx > 0) { addItem("\251gen", StringList(ID3v1::genre(idx - 1))); } } }
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); } }
MP4::Tag::Tag(File *file, MP4::Atoms *atoms) { d = new TagPrivate; d->file = file; d->atoms = atoms; MP4::Atom *ilst = atoms->find("moov", "udta", "meta", "ilst"); if(!ilst) { //debug("Atom moov.udta.meta.ilst not found."); return; } for(unsigned int i = 0; i < ilst->children.size(); i++) { MP4::Atom *atom = ilst->children[i]; file->seek(atom->offset + 8); if(atom->name == "----") { parseFreeForm(atom, file); } else if(atom->name == "trkn" || atom->name == "disk") { parseIntPair(atom, file); } else if(atom->name == "cpil" || atom->name == "pgap" || atom->name == "pcst") { parseBool(atom, file); } else if(atom->name == "tmpo") { parseInt(atom, file); } else if(atom->name == "gnre") { parseGnre(atom, file); } else if(atom->name == "covr") { //Added for artwork support in PlayerKit. ByteVectorList data = parseData(atom, file); if(data.size() > 0) { d->items.insert(atom->name, data); } } else { parseText(atom, file); } } }
ByteVectorList ByteVectorList::split( const ByteVector &v, const ByteVector &pattern, size_t byteAlign, size_t max) { ByteVectorList l; size_t previousOffset = 0; for(size_t offset = v.find(pattern, 0, byteAlign); offset != ByteVector::npos() && (max == 0 || max > l.size() + 1); offset = v.find(pattern, offset + pattern.size(), byteAlign)) { if(offset - previousOffset >= 1) l.append(v.mid(previousOffset, offset - previousOffset)); else l.append(ByteVector()); previousOffset = offset + pattern.size(); } if(previousOffset < v.size()) l.append(v.mid(previousOffset, v.size() - previousOffset)); return l; }
ByteVectorList ByteVectorList::split(const ByteVector &v, const ByteVector &pattern, int byteAlign, int max) { ByteVectorList l; uint previousOffset = 0; for(int offset = v.find(pattern, 0, byteAlign); offset != -1 && (max == 0 || max > int(l.size()) + 1); offset = v.find(pattern, offset + pattern.size(), byteAlign)) { if(offset - previousOffset > 1) l.append(v.mid(previousOffset, offset - previousOffset)); else l.append(ByteVector::null); previousOffset = offset + pattern.size(); } if(previousOffset < v.size()) l.append(v.mid(previousOffset, v.size() - previousOffset)); return l; }
List<Ogg::Page *> Ogg::Page::paginate(const ByteVectorList &packets, PaginationStrategy strategy, unsigned int streamSerialNumber, int firstPage, bool firstPacketContinued, bool lastPacketCompleted, bool containsLastPacket) { // SplitSize must be a multiple of 255 in order to get the lacing values right // create pages of about 8KB each static const unsigned int SplitSize = 32 * 255; // Force repagination if the packets are too large for a page. if(strategy != Repaginate) { size_t totalSize = packets.size(); for(ByteVectorList::ConstIterator it = packets.begin(); it != packets.end(); ++it) totalSize += it->size(); if(totalSize > 255 * 255) strategy = Repaginate; } List<Page *> l; // Handle creation of multiple pages with appropriate pagination. if(strategy == Repaginate) { int pageIndex = firstPage; for(ByteVectorList::ConstIterator it = packets.begin(); it != packets.end(); ++it) { const bool lastPacketInList = (it == --packets.end()); // mark very first packet? bool continued = (firstPacketContinued && it == packets.begin()); unsigned int pos = 0; while(pos < it->size()) { const bool lastSplit = (pos + SplitSize >= it->size()); ByteVectorList packetList; packetList.append(it->mid(pos, SplitSize)); l.append(new Page(packetList, streamSerialNumber, pageIndex, continued, lastSplit && (lastPacketInList ? lastPacketCompleted : true), lastSplit && (containsLastPacket && lastPacketInList))); pageIndex++; continued = true; pos += SplitSize; } } } else { l.append(new Page(packets, streamSerialNumber, firstPage, firstPacketContinued, lastPacketCompleted, containsLastPacket)); } return l; }
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; }