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); }
ByteVector Ogg::Page::render() const { ByteVector data; data.append(d->header.render()); if(d->packets.isEmpty()) { if(d->file) { d->file->seek(d->packetOffset); data.append(d->file->readBlock(d->dataSize)); } else debug("Ogg::Page::render() -- this page is empty!"); } else { ByteVectorList::ConstIterator it = d->packets.begin(); for(; it != d->packets.end(); ++it) data.append(*it); } // Compute and set the checksum for the Ogg page. The checksum is taken over // the entire page with the 4 bytes reserved for the checksum zeroed and then // inserted in bytes 22-25 of the page header. ByteVector checksum = ByteVector::fromUInt(data.checksum(), false); for(int i = 0; i < 4; i++) data[i + 22] = checksum[i]; return data; }
CryptoKey::CryptoKey(HCRYPTPROV cryptProv, const ByteVector& keyMaterial, const ByteVector& iv) :handle(NULL) { if (keyMaterial.size() != 0x10) throw logic_error("Invalid key length. Expected 128b"); if (iv.size() != 0x10) throw logic_error("Invalid IV length. Expected 128b"); byte_t blobHeader[] = { // Header 0x08, //plaintextblob CUR_BLOB_VERSION, 0x00, 0x00, ALG_SID_AES_128, 0x66, 0x00, 0x00, //ALG_ID 0x10, 0x00, 0x00, 0x00}; //key length in bytes ByteVector keyToImport; keyToImport.append(blobHeader, sizeof(blobHeader)); keyToImport.append(keyMaterial); // import key TOE(CryptImportKey(cryptProv, keyToImport.c_ptr(), static_cast<DWORD>(keyToImport.size()), 0, 0, &handle), "CryptImportKey"); // set IV TOE(CryptSetKeyParam(handle, KP_IV, const_cast<byte_t*>(iv.c_ptr()), 0), "CryptSetKeyParam(IV)"); }
ByteVector Header::render() const { ByteVector v; // add the file identifier -- "ID3" v.append(fileIdentifier()); // add the version number -- we always render a 2.4.0 tag regardless of what // the tag originally was. v.append(char(4)); v.append(char(0)); // Currently we don't actually support writing extended headers, footers or // unsynchronized tags, make sure that the flags are set accordingly. d->extendedHeader = false; d->footerPresent = false; d->unsynchronisation = false; // render and add the flags std::bitset<8> flags; flags[7] = d->unsynchronisation; flags[6] = d->extendedHeader; flags[5] = d->experimentalIndicator; flags[4] = d->footerPresent; v.append(char(flags.to_ulong())); // add the size v.append(SynchData::fromUInt(d->tagSize)); return v; }
ByteVector Ogg::PageHeader::lacingValues() const { ByteVector data; List<int> sizes = d->packetSizes; for(List<int>::ConstIterator it = sizes.begin(); it != sizes.end(); ++it) { // The size of a packet in an Ogg page is indicated by a series of "lacing // values" where the sum of the values is the packet size in bytes. Each of // these values is a byte. A value of less than 255 (0xff) indicates the end // of the packet. div_t n = div(*it, 255); for(int i = 0; i < n.quot; i++) data.append(char(uchar(255))); List<int>::ConstIterator last = sizes.end(); --last; if(it != last || d->lastPacketCompleted) data.append(char(uchar(n.rem))); } return data; }
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. ByteVector tagData; if(version != 3 && version != 4) { debug("Unknown ID3v2 version, using ID3v2.4"); version = 4; } // TODO: Render the extended header. // Loop through the frames rendering them and adding them to the tagData. FrameList newFrames; newFrames.setAutoDelete(true); FrameList frameList; if(version == 4) { frameList = d->frameList; } else { downgradeFrames(&frameList, &newFrames); } for(FrameList::Iterator it = frameList.begin(); it != frameList.end(); it++) { (*it)->header()->setVersion(version); if((*it)->header()->frameID().size() != 4) { debug("A frame of unsupported or unknown type \'" + String((*it)->header()->frameID()) + "\' has been discarded"); continue; } if(!(*it)->header()->tagAlterPreservation()) tagData.append((*it)->render()); } // Compute the amount of padding, and append that to tagData. uint paddingSize = 0; uint originalSize = d->header.tagSize(); if(tagData.size() < originalSize) paddingSize = originalSize - tagData.size(); else paddingSize = 1024; tagData.append(ByteVector(paddingSize, char(0))); // Set the version and data size. d->header.setMajorVersion(version); d->header.setTagSize(tagData.size()); // TODO: This should eventually include d->footer->render(). return d->header.render() + tagData; }
ByteVector PrivateFrame::renderFields() const { ByteVector v; v.append(d->owner.data(String::Latin1)); v.append(textDelimiter(String::Latin1)); v.append(d->data); return v; }
ByteVector UniqueFileIdentifierFrame::renderFields() const { ByteVector data; data.append(d->owner.data(String::Latin1)); data.append(char(0)); data.append(d->identifier); return data; }
ByteVector APE::Item::render() const { ByteVector data; TagLib::uint flags = ((d->readOnly) ? 1 : 0) | (d->type << 1); ByteVector value; if(isEmpty()) return data; if(d->type == Text) { StringList::ConstIterator it = d->text.begin(); value.append(it->data(String::UTF8)); it++; for(; it != d->text.end(); ++it) { value.append('\0'); value.append(it->data(String::UTF8)); } d->value = value; } else value.append(d->value); data.append(ByteVector::fromUInt(value.size(), false)); data.append(ByteVector::fromUInt(flags, false)); data.append(d->key.data(String::UTF8)); data.append(ByteVector('\0')); data.append(value); return data; }
ByteVector SynchronizedLyricsFrame::renderFields() const { ByteVector v; String::Type encoding = d->textEncoding; encoding = checkTextEncoding(d->description, encoding); for(SynchedTextList::ConstIterator it = d->synchedText.begin(); it != d->synchedText.end(); ++it) { encoding = checkTextEncoding(it->text, encoding); } v.append(char(encoding)); v.append(d->language.size() == 3 ? d->language : "XXX"); v.append(char(d->timestampFormat)); v.append(char(d->type)); v.append(d->description.data(encoding)); v.append(textDelimiter(encoding)); for(SynchedTextList::ConstIterator it = d->synchedText.begin(); it != d->synchedText.end(); ++it) { const SynchedText &entry = *it; v.append(entry.text.data(encoding)); v.append(textDelimiter(encoding)); v.append(ByteVector::fromUInt(entry.time)); } return v; }
ByteVector PopularimeterFrame::renderFields() const { ByteVector data; data.append(d->email.data(String::Latin1)); data.append(textDelimiter(String::Latin1)); data.append(char(d->rating)); data.append(ByteVector::fromUInt(d->counter)); return data; }
ByteVector CommentsFrame::renderFields() const { ByteVector v; v.append(char(d->textEncoding)); v.append(d->language.size() == 3 ? d->language : " "); v.append(d->description.data(d->textEncoding)); v.append(textDelimiter(d->textEncoding)); v.append(d->text.data(d->textEncoding)); return v; }
ByteVector UnsynchronizedLyricsFrame::renderFields() const { ByteVector v; v.append(char(d->textEncoding)); v.append(d->language.size() == 3 ? d->language : "XXX"); v.append(d->description.data(d->textEncoding)); v.append(textDelimiter(d->textEncoding)); v.append(d->text.data(d->textEncoding)); return v; }
bool MP4::Tag::save() { ByteVector data; for(MP4::ItemMap::ConstIterator it = d->items.begin(); it != d->items.end(); ++it) { const String name = it->first; if(name.startsWith("----")) { data.append(renderFreeForm(name, it->second)); } else if(name == "trkn") { data.append(renderIntPair(name.data(String::Latin1), it->second)); } else if(name == "disk") { data.append(renderIntPairNoTrailing(name.data(String::Latin1), it->second)); } else if(name == "cpil" || name == "pgap" || name == "pcst" || name == "hdvd") { data.append(renderBool(name.data(String::Latin1), it->second)); } else if(name == "tmpo") { data.append(renderInt(name.data(String::Latin1), it->second)); } else if(name == "tvsn" || name == "tves" || name == "cnID" || name == "sfID" || name == "atID" || name == "geID") { data.append(renderUInt(name.data(String::Latin1), it->second)); } else if(name == "plID") { data.append(renderLongLong(name.data(String::Latin1), it->second)); } else if(name == "stik" || name == "rtng" || name == "akID") { data.append(renderByte(name.data(String::Latin1), it->second)); } else if(name == "covr") { data.append(renderCovr(name.data(String::Latin1), it->second)); } else if(name.size() == 4){ data.append(renderText(name.data(String::Latin1), it->second)); } else { debug("MP4: Unknown item name \"" + name + "\""); } } data = renderAtom("ilst", data); AtomList path = d->atoms->path("moov", "udta", "meta", "ilst"); if(path.size() == 4) { saveExisting(data, path); } else { saveNew(data); } return true; }
ByteVector UserUrlLinkFrame::renderFields() const { ByteVector v; String::Type encoding = checkTextEncoding(d->description, d->textEncoding); v.append(char(encoding)); v.append(d->description.data(encoding)); v.append(textDelimiter(encoding)); v.append(url().data(String::Latin1)); return v; }
void MP4::Tag::saveExisting(ByteVector data, const AtomList &path) { AtomList::ConstIterator it = path.end(); MP4::Atom *ilst = *(--it); long offset = ilst->offset; long length = ilst->length; MP4::Atom *meta = *(--it); AtomList::ConstIterator index = meta->children.find(ilst); // check if there is an atom before 'ilst', and possibly use it as padding if(index != meta->children.begin()) { AtomList::ConstIterator prevIndex = index; prevIndex--; MP4::Atom *prev = *prevIndex; if(prev->name == "free") { offset = prev->offset; length += prev->length; } } // check if there is an atom after 'ilst', and possibly use it as padding AtomList::ConstIterator nextIndex = index; nextIndex++; if(nextIndex != meta->children.end()) { MP4::Atom *next = *nextIndex; if(next->name == "free") { length += next->length; } } long delta = data.size() - length; if(delta > 0 || (delta < 0 && delta > -8)) { data.append(padIlst(data)); delta = data.size() - length; } else if(delta < 0) { data.append(padIlst(data, -delta - 8)); delta = 0; } d->file->insert(data, offset, length); if(delta) { updateParents(path, delta, 1); updateOffsets(delta, offset); } }
ByteVector ASF::Attribute::render(const String &name, int kind) const { ByteVector data; switch (d->type) { case WordType: data.append(ByteVector::fromShort(d->shortValue, false)); break; case BoolType: if(kind == 0) { data.append(ByteVector::fromUInt(d->boolValue ? 1 : 0, false)); } else { data.append(ByteVector::fromShort(d->boolValue ? 1 : 0, false)); } break; case DWordType: data.append(ByteVector::fromUInt(d->intValue, false)); break; case QWordType: data.append(ByteVector::fromLongLong(d->longLongValue, false)); break; case UnicodeType: data.append(File::renderString(d->stringValue)); break; case BytesType: if(d->pictureValue.isValid()) { data.append(d->pictureValue.render()); break; } case GuidType: data.append(d->byteVectorValue); break; } if(kind == 0) { data = File::renderString(name, true) + ByteVector::fromShort((int)d->type, false) + ByteVector::fromShort(data.size(), false) + data; } else { ByteVector nameData = File::renderString(name); data = ByteVector::fromShort(kind == 2 ? d->language : 0, false) + ByteVector::fromShort(d->stream, false) + ByteVector::fromShort(nameData.size(), false) + ByteVector::fromShort((int)d->type, false) + ByteVector::fromUInt(data.size(), false) + nameData + data; } return data; }
ByteVector ByteVectorList::toByteVector(const ByteVector &separator) const { ByteVector v; ConstIterator it = begin(); while(it != end()) { v.append(*it); it++; if(it != end()) v.append(separator); } return v; }
void RIFF::File::writeChunk(const ByteVector &name, const ByteVector &data, ulong offset, ulong replace, uint leadingPadding) { ByteVector combined; if(leadingPadding) { combined.append(ByteVector(leadingPadding, '\x00')); } combined.append(name); combined.append(ByteVector::fromUInt(data.size(), d->endianness == BigEndian)); combined.append(data); if((data.size() & 0x01) != 0) { combined.append('\x00'); } insert(combined, offset, replace); }
ByteVector Frame::textDelimiter(String::Type t) { ByteVector d = char(0); if(t == String::UTF16 || t == String::UTF16BE || t == String::UTF16LE) d.append(char(0)); return d; }
bool ASF::File::save() { if(readOnly()) { debug("ASF: File is read-only."); 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]; bool largeValue = attribute.dataSize() > 65535; if(!inExtendedContentDescriptionObject && !largeValue && attribute.language() == 0 && attribute.stream() == 0) { d->extendedContentDescriptionObject->attributeData.append(attribute.render(name)); inExtendedContentDescriptionObject = true; } else if(!inMetadataObject && !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, d->size); return true; }
void CryptoProxy::encrypt(CryptoKey* key, const ByteVector& data, ByteVector& encryptedData) { if ((data.length() % 16) > 0) throw runtime_error("encrypt: incorrect data length"); encryptedData = data; //Crypto encrypts in-place // NOTE: do not reserve block for padding, specify final = FALSE instead //encryptedData.append(0x00, 16); // add one extra block as MS wants it for padding const DWORD bytesToEncrypt = static_cast<DWORD>(data.size()); DWORD dataSize = bytesToEncrypt; try { TOE(CryptEncrypt(*key, 0, FALSE/*final*/, 0/*flags*/, &encryptedData.front(), &dataSize, static_cast<DWORD>(encryptedData.size())), "CryptEncrypt 1st"); } catch (WinApiError& e) { // larger buffer is required?? if (e.getErr() == ERROR_MORE_DATA) { encryptedData.append(0x00, dataSize - encryptedData.size()); // try again, no second catch this time dataSize = bytesToEncrypt; //set again to input data length TOE(CryptEncrypt(*key, 0, FALSE/*final*/, 0/*flags*/, &encryptedData.front(), &dataSize, static_cast<DWORD>(encryptedData.size())), "CryptEncrypt 2nd"); } else throw; // another error -> re-throw } // strip the padding encryptedData.resize(bytesToEncrypt); }
Ogg::Page::Page(const ByteVectorList &packets, uint streamSerialNumber, int pageNumber, bool firstPacketContinued, bool lastPacketCompleted, bool containsLastPacket) { d = new PagePrivate; ByteVector data; List<int> packetSizes; d->header.setFirstPageOfStream(pageNumber == 0 && !firstPacketContinued); d->header.setLastPageOfStream(containsLastPacket); d->header.setFirstPacketContinued(firstPacketContinued); d->header.setLastPacketCompleted(lastPacketCompleted); d->header.setStreamSerialNumber(streamSerialNumber); d->header.setPageSequenceNumber(pageNumber); // Build a page from the list of packets. for(ByteVectorList::ConstIterator it = packets.begin(); it != packets.end(); ++it) { packetSizes.append((*it).size()); data.append(*it); } d->packets = packets; d->header.setPacketSizes(packetSizes); }
ByteVector UnsynchronizedLyricsFrame::renderFields() const { ByteVector v; //=== Alex. There is a problem with the Writing of UNICODE strings. That's why we manually set the encoding String::Type encoding = String::UTF8; v.append(char(encoding)); v.append(d->language.size() == 3 ? d->language : "XXX"); v.append(d->description.data(encoding)); v.append(textDelimiter(encoding)); v.append(d->text.data(encoding)); //=== Alex END. There is a problem return v; }
bool Ogg::FLAC::File::save() { d->xiphCommentData = d->comment->render(false); // Create FLAC metadata-block: // Put the size in the first 32 bit (I assume no more than 24 bit are used) ByteVector v = ByteVector::fromUInt(d->xiphCommentData.size()); // Set the type of the metadata-block to be a Xiph / Vorbis comment v[0] = 4; // Append the comment-data after the 32 bit header v.append(d->xiphCommentData); // Save the packet at the old spot // FIXME: Use padding if size is increasing setPacket(d->commentPacket, v); return Ogg::File::save(); }
ByteVector MP4::Tag::renderFreeForm(const String &name, MP4::Item &item) { 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))); StringList value = item.toStringList(); for(unsigned int i = 0; i < value.size(); i++) { data.append(renderAtom("data", ByteVector::fromUInt(1) + ByteVector(4, '\0') + value[i].data(String::UTF8))); } return renderAtom("----", data); }
void IpmiPayload::serializeRmcpp(ByteVector& out, const IpmiPayloadData& payload) { // 2-bytes length out += static_cast<byte_t>(payload.data.length() & 0xff); out += static_cast<byte_t>((payload.data.length() >> 8) & 0xff); out.append(payload.data); }
ByteVector CommentsFrame::renderFields() const { ByteVector v; String::Type encoding = d->textEncoding; encoding = checkEncoding(d->description, encoding); encoding = checkEncoding(d->text, encoding); v.append(char(encoding)); v.append(d->language.size() == 3 ? d->language : "XXX"); v.append(d->description.data(encoding)); v.append(textDelimiter(encoding)); v.append(d->text.data(encoding)); return v; }
ByteVector OwnershipFrame::renderFields() const { StringList sl; sl.append(d->seller); const String::Type encoding = checkTextEncoding(sl, d->textEncoding); ByteVector v; v.append(char(encoding)); v.append(d->pricePaid.data(String::Latin1)); v.append(textDelimiter(String::Latin1)); v.append(d->datePurchased.data(String::Latin1)); v.append(d->seller.data(encoding)); return v; }
ByteVector TableOfContentsFrame::renderFields() const { ByteVector data; data.append(d->elementID); data.append('\0'); char flags = 0; if(d->isTopLevel) flags += 2; if(d->isOrdered) flags += 1; data.append(flags); data.append((char)(entryCount())); ByteVectorList::ConstIterator it = d->childElements.begin(); while(it != d->childElements.end()) { data.append(*it); data.append('\0'); it++; } FrameList l = d->embeddedFrameList; for(FrameList::ConstIterator it = l.begin(); it != l.end(); ++it) data.append((*it)->render()); return data; }