void ID3_TagHeader::Render(ID3_Writer& writer) const { writer.writeChars((uchar *) ID, strlen(ID)); writer.writeChar(ID3_V2SpecToVer(ID3V2_LATEST)); writer.writeChar(ID3_V2SpecToRev(ID3V2_LATEST)); // set the flags byte in the header writer.writeChar(static_cast<uchar>(_flags.get() & MASK8)); io::writeUInt28(writer, this->GetDataSize()); //now includes the extended header // now we render the extended header if (_flags.test(HEADER_FLAG_EXTENDED)) { if (this->GetSpec() == ID3V2_4_0) { io::writeUInt28(writer, 6); //write 4 bytes of v2.4.0 ext header containing size '6' io::writeBENumber(writer, 1, 1); //write that it has only one flag byte (value '1') io::writeBENumber(writer, 0, 1); //write flag byte with value '0' } else if (this->GetSpec() == ID3V2_3_0) { io::writeBENumber(writer, 6, sizeof(uint32)); for (size_t i = 0; i < 6; ++i) { if (writer.writeChar('\0') == ID3_Writer::END_OF_WRITER) { break; } } } // else //not implemented } }
void id3::v2::render(ID3_Writer& writer, const ID3_TagImpl& tag) { // There has to be at least one frame for there to be a tag... if (tag.NumFrames() == 0) { ID3D_WARNING( "id3::v2::render(): no frames to render" ); return; } ID3D_NOTICE( "id3::v2::render(): rendering" ); ID3_TagHeader hdr; hdr.SetSpec(tag.GetSpec()); hdr.SetExtended(tag.GetExtended()); hdr.SetExperimental(tag.GetExperimental()); // set up the encryption and grouping IDs // ... String frms; io::StringWriter frmWriter(frms); if (!tag.GetUnsync()) { ID3D_NOTICE( "id3::v2::render(): rendering frames" ); renderFrames(frmWriter, tag); hdr.SetUnsync(false); } else { ID3D_NOTICE( "id3::v2::render(): rendering unsynced frames" ); io::UnsyncedWriter uw(frmWriter); renderFrames(uw, tag); uw.flush(); ID3D_NOTICE( "id3::v2::render(): numsyncs = " << uw.getNumSyncs() ); hdr.SetUnsync(uw.getNumSyncs() > 0); } size_t frmSize = frms.size(); if (frmSize == 0) { ID3D_WARNING( "id3::v2::render(): rendered frame size is 0 bytes" ); return; } // zero the remainder of the buffer so that our padding bytes are zero luint nPadding = tag.PaddingSize(frmSize); ID3D_NOTICE( "id3::v2::render(): padding size = " << nPadding ); hdr.SetDataSize(frmSize + nPadding); hdr.Render(writer); writer.writeChars(frms.data(), frms.size()); for (size_t i = 0; i < nPadding; ++i) { if (writer.writeChar('\0') == ID3_Writer::END_OF_WRITER) { break; } } }
void ID3_TagHeader::Render(ID3_Writer& writer) const { writer.writeChars((uchar *) ID, strlen(ID)); writer.writeChar(ID3_V2SpecToVer(ID3V2_LATEST)); writer.writeChar(ID3_V2SpecToRev(ID3V2_LATEST)); // set the flags byte in the header writer.writeChar(static_cast<uchar>(_flags.get() & MASK8)); io::writeUInt28(writer, this->GetDataSize()); // now we render the extended header if (_flags.test(EXTENDED)) { io::writeBENumber(writer, _info->extended_bytes, sizeof(uint32)); } }
size_t io::writeTrailingSpaces(ID3_Writer& writer, String buf, size_t len) { ID3_Writer::pos_type beg = writer.getCur(); ID3_Writer::size_type strLen = buf.size(); ID3_Writer::size_type size = min((unsigned int)len, (unsigned int)strLen); writer.writeChars(buf.data(), size); for (; size < len; ++size) { writer.writeChar('\0'); } return writer.getCur() - beg; }
void id3::v1::render(ID3_Writer& writer, const ID3_TagImpl& tag) { writer.writeChars("TAG", 3); io::writeTrailingSpaces(writer, id3::v2::getTitle(tag), ID3_V1_LEN_TITLE); io::writeTrailingSpaces(writer, id3::v2::getArtist(tag), ID3_V1_LEN_ARTIST); io::writeTrailingSpaces(writer, id3::v2::getAlbum(tag), ID3_V1_LEN_ALBUM); io::writeTrailingSpaces(writer, id3::v2::getYear(tag), ID3_V1_LEN_YEAR); size_t track = id3::v2::getTrackNum(tag); String comment = id3::v2::getV1Comment(tag); if (track > 0) { io::writeTrailingSpaces(writer, comment, ID3_V1_LEN_COMMENT - 2); writer.writeChar('\0'); writer.writeChar((char) track); } else { io::writeTrailingSpaces(writer, comment, ID3_V1_LEN_COMMENT); } writer.writeChar((char) id3::v2::getGenreNum(tag)); }
size_t io::writeString(ID3_Writer& writer, String data) { size_t size = writeText(writer, data); writer.writeChar('\0'); return size + 1; }
void ID3_FrameImpl::Render(ID3_Writer& writer) const { // Return immediately if we have no fields, which (usually) means we're // trying to render a frame which has been Cleared or hasn't been initialized if (!this->NumFields()) { return; } ID3_FrameHeader hdr; const size_t hdr_size = hdr.Size(); // 1. Write out the field data to the buffer, with the assumption that // we won't be decompressing, since this is the usual behavior String flds; io::StringWriter fldWriter(flds); size_t origSize = 0; if (!this->GetCompression()) { renderFields(fldWriter, *this); origSize = flds.size(); ID3D_NOTICE ( "ID3_FrameImpl::Render(): uncompressed fields" ); } else { io::CompressedWriter cr(fldWriter); renderFields(cr, *this); cr.flush(); origSize = cr.getOrigSize(); ID3D_NOTICE ( "ID3_FrameImpl::Render(): compressed fields, orig size = " << origSize ); } size_t fldSize = flds.size(); ID3D_NOTICE ( "ID3_FrameImpl::Render(): field size = " << fldSize ); // No need to not write empty frames, why would we not? They can be used to fill up padding space // which is even recommended in the id3 spec. // if (fldSize == 0) // { // ID3D_WARNING ( "ID3_FrameImpl::Render(): no field data" ); // return; // } // determine which flags need to be set uchar eID = this->GetEncryptionID(), gID = this->GetGroupingID(); ID3_FrameID fid = this->GetID(); if (fid == ID3FID_NOFRAME) { const char *tid = this->GetTextID(); hdr.SetUnknownFrame(tid); } else { hdr.SetFrameID(fid); } hdr.SetEncryption(eID > 0); hdr.SetGrouping(gID > 0); hdr.SetCompression(origSize > fldSize); hdr.SetDataSize(fldSize + ((hdr.GetCompression() ? 4 : 0) + (hdr.GetEncryption() ? 1 : 0) + (hdr.GetGrouping() ? 1 : 0))); // write out the header hdr.Render(writer); if (fldSize != 0) { // No-man's land! Not part of the header, not part of the data if (hdr.GetCompression()) { io::writeBENumber(writer, origSize, sizeof(uint32)); ID3D_NOTICE( "ID3_FrameImpl::Render(): frame is compressed, wrote origSize = " << origSize ); } if (hdr.GetEncryption()) { writer.writeChar(eID); ID3D_NOTICE( "ID3_FrameImpl::Render(): frame is compressed, encryption id = " << eID ); } if (hdr.GetGrouping()) { writer.writeChar(gID); ID3D_NOTICE( "ID3_FrameImpl::Render(): frame is compressed, grouping id = " << gID ); } // Write the field data writer.writeChars(flds.data(), fldSize); } _changed = false; }