00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include <memory.h>
00029 #include "tag_impl.h"
00030 #include "helpers.h"
00031 #include "writers.h"
00032 #include "id3/io_decorators.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
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
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
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
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
00197 if (! _is_padded)
00198 {
00199 return 0;
00200 }
00201
00202
00203
00204
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
00217
00218
00219 tempSize = ((tempSize / ID3_PADMULTIPLE) + 1) * ID3_PADMULTIPLE;
00220
00221
00222 newSize = tempSize - ID3_GetDataSize(*this) - this->GetAppendedBytes () -
00223 ID3_TagHeader::SIZE;
00224 }
00225
00226 return newSize - curSize;
00227 }
00228