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 #if defined HAVE_CONFIG_H
00028 #include <config.h>
00029 #endif
00030
00031
00032
00033 #include <stdlib.h>
00034 #include <string.h>
00035 #include <memory.h>
00036 #include "tag_impl.h"
00037 #include "helpers.h"
00038 #include "utils.h"
00039 #include "writers.h"
00040 #include "io_decorators.h"
00041 #include "io_helpers.h"
00042 #include "io_strings.h"
00043
00044 #if defined HAVE_SYS_PARAM_H
00045 #include <sys/param.h>
00046 #endif
00047
00048 using namespace dami;
00049
00050 void id3::v1::render(ID3_Writer& writer, const ID3_TagImpl& tag)
00051 {
00052 writer.writeChars("TAG", 3);
00053
00054 io::writeTrailingSpaces(writer, id3::v2::getTitle(tag), ID3_V1_LEN_TITLE);
00055 io::writeTrailingSpaces(writer, id3::v2::getArtist(tag), ID3_V1_LEN_ARTIST);
00056 io::writeTrailingSpaces(writer, id3::v2::getAlbum(tag), ID3_V1_LEN_ALBUM);
00057 io::writeTrailingSpaces(writer, id3::v2::getYear(tag), ID3_V1_LEN_YEAR);
00058
00059 size_t track = id3::v2::getTrackNum(tag);
00060 String comment = id3::v2::getV1Comment(tag);
00061 if (track > 0)
00062 {
00063 io::writeTrailingSpaces(writer, comment, ID3_V1_LEN_COMMENT - 2);
00064 writer.writeChar('\0');
00065 writer.writeChar((char) track);
00066 }
00067 else
00068 {
00069 io::writeTrailingSpaces(writer, comment, ID3_V1_LEN_COMMENT);
00070 }
00071 writer.writeChar((char) id3::v2::getGenreNum(tag));
00072 }
00073
00074 namespace
00075 {
00076 void renderFrames(ID3_Writer& writer, const ID3_TagImpl& tag)
00077 {
00078 for (ID3_TagImpl::const_iterator iter = tag.begin(); iter != tag.end(); ++iter)
00079 {
00080 const ID3_Frame* frame = *iter;
00081 if (frame) frame->Render(writer);
00082 }
00083 }
00084 }
00085
00086 void id3::v2::render(ID3_Writer& writer, const ID3_TagImpl& tag)
00087 {
00088
00089 if (tag.NumFrames() == 0)
00090 {
00091 ID3D_WARNING( "id3::v2::render(): no frames to render" );
00092 return;
00093 }
00094
00095 ID3D_NOTICE( "id3::v2::render(): rendering" );
00096 ID3_TagHeader hdr;
00097 hdr.SetSpec(tag.GetSpec());
00098 hdr.SetExtended(tag.GetExtended());
00099 hdr.SetExperimental(tag.GetExperimental());
00100
00101
00102
00103
00104 String frms;
00105 io::StringWriter frmWriter(frms);
00106 if (!tag.GetUnsync())
00107 {
00108 ID3D_NOTICE( "id3::v2::render(): rendering frames" );
00109 renderFrames(frmWriter, tag);
00110 hdr.SetUnsync(false);
00111 }
00112 else
00113 {
00114 ID3D_NOTICE( "id3::v2::render(): rendering unsynced frames" );
00115 io::UnsyncedWriter uw(frmWriter);
00116 renderFrames(uw, tag);
00117 uw.flush();
00118 ID3D_NOTICE( "id3::v2::render(): numsyncs = " << uw.getNumSyncs() );
00119 hdr.SetUnsync(uw.getNumSyncs() > 0);
00120 }
00121 size_t frmSize = frms.size();
00122 if (frmSize == 0)
00123 {
00124 ID3D_WARNING( "id3::v2::render(): rendered frame size is 0 bytes" );
00125 return;
00126 }
00127
00128
00129 luint nPadding = tag.PaddingSize(frmSize);
00130 ID3D_NOTICE( "id3::v2::render(): padding size = " << nPadding );
00131 hdr.SetDataSize(frmSize + nPadding);
00132
00133 hdr.Render(writer);
00134
00135 writer.writeChars(frms.data(), frms.size());
00136
00137 for (size_t i = 0; i < nPadding; ++i)
00138 {
00139 if (writer.writeChar('\0') == ID3_Writer::END_OF_WRITER)
00140 {
00141 break;
00142 }
00143 }
00144 }
00145
00146 size_t ID3_TagImpl::Size() const
00147 {
00148 if (this->NumFrames() == 0)
00149 {
00150 return 0;
00151 }
00152 ID3_TagHeader hdr;
00153
00154 hdr.SetSpec(this->GetSpec());
00155 size_t bytesUsed = hdr.Size();
00156
00157 size_t frameBytes = 0;
00158 for (const_iterator cur = _frames.begin(); cur != _frames.end(); ++cur)
00159 {
00160 if (*cur)
00161 {
00162 (*cur)->SetSpec(this->GetSpec());
00163 frameBytes += (*cur)->Size();
00164 }
00165 }
00166
00167 if (!frameBytes)
00168 {
00169 return 0;
00170 }
00171
00172 bytesUsed += frameBytes;
00173
00174 if (this->GetUnsync())
00175 {
00176 bytesUsed += bytesUsed / 3;
00177 }
00178
00179 bytesUsed += this->PaddingSize(bytesUsed);
00180 return bytesUsed;
00181 }
00182
00183
00184 void ID3_TagImpl::RenderExtHeader(uchar *buffer)
00185 {
00186 if (this->GetSpec() == ID3V2_3_0)
00187 {
00188 }
00189
00190 return ;
00191 }
00192
00193
00194 #define ID3_PADMULTIPLE (2048)
00195 #define ID3_PADMAX (4096)
00196
00197
00198 size_t ID3_TagImpl::PaddingSize(size_t curSize) const
00199 {
00200 luint newSize = 0;
00201
00202
00203 if (! _is_padded || !this->GetPrependedBytes())
00204 {
00205 return 0;
00206 }
00207
00208
00209
00210
00211 if (this->GetPrependedBytes() && (this->GetPrependedBytes() >= curSize) &&
00212 (this->GetPrependedBytes() - curSize) < ID3_PADMAX)
00213 {
00214 newSize = this->GetPrependedBytes();
00215 }
00216 else
00217 {
00218 luint tempSize = curSize + ID3_GetDataSize(*this);
00219
00220
00221
00222
00223 tempSize = ((tempSize / ID3_PADMULTIPLE) + 1) * ID3_PADMULTIPLE;
00224
00225
00226 newSize = tempSize - ID3_GetDataSize(*this);
00227 }
00228
00229 return newSize - curSize;
00230 }