id3lib
3.8.3
|
00001 // $Id: tag_render.cpp,v 1.44 2002/07/31 13:20:49 t1mpy Exp $ 00002 00003 // id3lib: a C++ library for creating and manipulating id3v1/v2 tags 00004 // Copyright 1999, 2000 Scott Thomas Haug 00005 // Copyright 2002 Thijmen Klok (thijmen@id3lib.org) 00006 00007 // This library is free software; you can redistribute it and/or modify it 00008 // under the terms of the GNU Library General Public License as published by 00009 // the Free Software Foundation; either version 2 of the License, or (at your 00010 // option) any later version. 00011 // 00012 // This library is distributed in the hope that it will be useful, but WITHOUT 00013 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 00014 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public 00015 // License for more details. 00016 // 00017 // You should have received a copy of the GNU Library General Public License 00018 // along with this library; if not, write to the Free Software Foundation, 00019 // Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 00020 00021 // The id3lib authors encourage improvements and optimisations to be sent to 00022 // the id3lib coordinator. Please see the README file for details on where to 00023 // send such submissions. See the AUTHORS file for a list of people who have 00024 // contributed to id3lib. See the ChangeLog file for a list of changes to 00025 // id3lib. These files are distributed with id3lib at 00026 // http://download.sourceforge.net/id3lib/ 00027 00028 #include <memory.h> 00029 #include "tag_impl.h" //has <stdio.h> "tag.h" "header_tag.h" "frame.h" "field.h" "spec.h" "id3lib_strings.h" "utils.h" 00030 #include "helpers.h" 00031 #include "writers.h" 00032 #include "id3/io_decorators.h" //has "readers.h" "io_helpers.h" "utils.h" 00033 #include "io_helpers.h" 00034 #include "io_strings.h" 00035 00036 #if defined HAVE_SYS_PARAM_H 00037 #include <sys/param.h> 00038 #endif 00039 00040 using namespace dami; 00041 00042 void id3::v1::render(ID3_Writer& writer, const ID3_TagImpl& tag) 00043 { 00044 writer.writeChars("TAG", 3); 00045 00046 io::writeTrailingSpaces(writer, id3::v2::getTitle(tag), ID3_V1_LEN_TITLE); 00047 io::writeTrailingSpaces(writer, id3::v2::getArtist(tag), ID3_V1_LEN_ARTIST); 00048 io::writeTrailingSpaces(writer, id3::v2::getAlbum(tag), ID3_V1_LEN_ALBUM); 00049 io::writeTrailingSpaces(writer, id3::v2::getYear(tag), ID3_V1_LEN_YEAR); 00050 00051 size_t track = id3::v2::getTrackNum(tag); 00052 String comment = id3::v2::getV1Comment(tag); 00053 if (track > 0) 00054 { 00055 io::writeTrailingSpaces(writer, comment, ID3_V1_LEN_COMMENT - 2); 00056 writer.writeChar('\0'); 00057 writer.writeChar((char) track); 00058 } 00059 else 00060 { 00061 io::writeTrailingSpaces(writer, comment, ID3_V1_LEN_COMMENT); 00062 } 00063 writer.writeChar((char) id3::v2::getGenreNum(tag)); 00064 } 00065 00066 namespace 00067 { 00068 void renderFrames(ID3_Writer& writer, const ID3_TagImpl& tag) 00069 { 00070 for (ID3_TagImpl::const_iterator iter = tag.begin(); iter != tag.end(); ++iter) 00071 { 00072 const ID3_Frame* frame = *iter; 00073 if (frame) frame->Render(writer); 00074 } 00075 } 00076 } 00077 00078 void id3::v2::render(ID3_Writer& writer, const ID3_TagImpl& tag) 00079 { 00080 // There has to be at least one frame for there to be a tag... 00081 if (tag.NumFrames() == 0) 00082 { 00083 ID3D_WARNING( "id3::v2::render(): no frames to render" ); 00084 return; 00085 } 00086 00087 ID3D_NOTICE( "id3::v2::render(): rendering" ); 00088 ID3_TagHeader hdr; 00089 hdr.SetSpec(tag.GetSpec()); 00090 hdr.SetExtended(tag.GetExtended()); 00091 hdr.SetExperimental(tag.GetExperimental()); 00092 hdr.SetFooter(tag.GetFooter()); 00093 00094 // set up the encryption and grouping IDs 00095 00096 // ... 00097 String frms; 00098 io::StringWriter frmWriter(frms); 00099 if (!tag.GetUnsync()) 00100 { 00101 ID3D_NOTICE( "id3::v2::render(): rendering frames" ); 00102 renderFrames(frmWriter, tag); 00103 hdr.SetUnsync(false); 00104 } 00105 else 00106 { 00107 ID3D_NOTICE( "id3::v2::render(): rendering unsynced frames" ); 00108 io::UnsyncedWriter uw(frmWriter); 00109 renderFrames(uw, tag); 00110 uw.flush(); 00111 ID3D_NOTICE( "id3::v2::render(): numsyncs = " << uw.getNumSyncs() ); 00112 hdr.SetUnsync(uw.getNumSyncs() > 0); 00113 } 00114 size_t frmSize = frms.size(); 00115 if (frmSize == 0) 00116 { 00117 ID3D_WARNING( "id3::v2::render(): rendered frame size is 0 bytes" ); 00118 return; 00119 } 00120 00121 // zero the remainder of the buffer so that our padding bytes are zero 00122 luint nPadding = tag.PaddingSize(frmSize); 00123 ID3D_NOTICE( "id3::v2::render(): padding size = " << nPadding ); 00124 00125 hdr.SetDataSize(frmSize + tag.GetExtendedBytes() + nPadding); 00126 00127 hdr.Render(writer); 00128 00129 writer.writeChars(frms.data(), frms.size()); 00130 00131 for (size_t i = 0; i < nPadding; ++i) 00132 { 00133 if (writer.writeChar('\0') == ID3_Writer::END_OF_WRITER) 00134 { 00135 break; 00136 } 00137 } 00138 } 00139 00140 size_t ID3_TagImpl::Size() const 00141 { 00142 if (this->NumFrames() == 0) 00143 { 00144 return 0; 00145 } 00146 ID3_TagHeader hdr; 00147 00148 hdr.SetSpec(this->GetSpec()); 00149 size_t bytesUsed = hdr.Size(); 00150 00151 size_t frameBytes = 0; 00152 for (const_iterator cur = _frames.begin(); cur != _frames.end(); ++cur) 00153 { 00154 if (*cur) 00155 { 00156 (*cur)->SetSpec(this->GetSpec()); 00157 frameBytes += (*cur)->Size(); 00158 } 00159 } 00160 00161 if (!frameBytes) 00162 { 00163 return 0; 00164 } 00165 00166 bytesUsed += frameBytes; 00167 // add 30% for sync 00168 if (this->GetUnsync()) 00169 { 00170 bytesUsed += bytesUsed / 3; 00171 } 00172 00173 bytesUsed += this->PaddingSize(bytesUsed); 00174 return bytesUsed; 00175 } 00176 00177 00178 void ID3_TagImpl::RenderExtHeader(uchar *buffer) 00179 { 00180 if (this->GetSpec() == ID3V2_3_0) 00181 { 00182 } 00183 00184 return ; 00185 } 00186 00187 00188 #define ID3_PADMULTIPLE (2048) 00189 #define ID3_PADMAX (4096) 00190 00191 00192 size_t ID3_TagImpl::PaddingSize(size_t curSize) const 00193 { 00194 luint newSize = 0; 00195 00196 // if padding is switched off 00197 if (! _is_padded) 00198 { 00199 return 0; 00200 } 00201 00202 // if the old tag was large enough to hold the new tag, then we will simply 00203 // pad out the difference - that way the new tag can be written without 00204 // shuffling the rest of the song file around 00205 if ((this->GetPrependedBytes()-ID3_TagHeader::SIZE > 0) && 00206 (this->GetPrependedBytes()-ID3_TagHeader::SIZE >= curSize) && 00207 (this->GetPrependedBytes()-ID3_TagHeader::SIZE - curSize) < ID3_PADMAX) 00208 { 00209 newSize = this->GetPrependedBytes()-ID3_TagHeader::SIZE; 00210 } 00211 else 00212 { 00213 luint tempSize = curSize + ID3_GetDataSize(*this) + 00214 this->GetAppendedBytes() + ID3_TagHeader::SIZE; 00215 00216 // this method of automatic padding rounds the COMPLETE FILE up to the 00217 // nearest 2K. If the file will already be an even multiple of 2K (with 00218 // the tag included) then we just add another 2K of padding 00219 tempSize = ((tempSize / ID3_PADMULTIPLE) + 1) * ID3_PADMULTIPLE; 00220 00221 // the size of the new tag is the new filesize minus the audio data 00222 newSize = tempSize - ID3_GetDataSize(*this) - this->GetAppendedBytes () - 00223 ID3_TagHeader::SIZE; 00224 } 00225 00226 return newSize - curSize; 00227 } 00228