id3lib 3.8.3
tag_render.cpp
Go to the documentation of this file.
1// $Id: tag_render.cpp,v 1.44 2002/07/31 13:20:49 t1mpy Exp $
2
3// id3lib: a C++ library for creating and manipulating id3v1/v2 tags
4// Copyright 1999, 2000 Scott Thomas Haug
5// Copyright 2002 Thijmen Klok (thijmen@id3lib.org)
6
7// This library is free software; you can redistribute it and/or modify it
8// under the terms of the GNU Library General Public License as published by
9// the Free Software Foundation; either version 2 of the License, or (at your
10// option) any later version.
11//
12// This library is distributed in the hope that it will be useful, but WITHOUT
13// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
15// License for more details.
16//
17// You should have received a copy of the GNU Library General Public License
18// along with this library; if not, write to the Free Software Foundation,
19// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20
21// The id3lib authors encourage improvements and optimisations to be sent to
22// the id3lib coordinator. Please see the README file for details on where to
23// send such submissions. See the AUTHORS file for a list of people who have
24// contributed to id3lib. See the ChangeLog file for a list of changes to
25// id3lib. These files are distributed with id3lib at
26// http://download.sourceforge.net/id3lib/
27
28#include <memory.h>
29#include "tag_impl.h" //has <stdio.h> "tag.h" "header_tag.h" "frame.h" "field.h" "spec.h" "id3lib_strings.h" "utils.h"
30#include "helpers.h"
31#include "writers.h"
32#include "id3/io_decorators.h" //has "readers.h" "io_helpers.h" "utils.h"
33#include "io_helpers.h"
34#include "io_strings.h"
35
36#if defined HAVE_SYS_PARAM_H
37#include <sys/param.h>
38#endif
39
40using namespace dami;
41
42void id3::v1::render(ID3_Writer& writer, const ID3_TagImpl& tag)
43{
44 writer.writeChars("TAG", 3);
45
46 io::writeTrailingSpaces(writer, id3::v2::getTitle(tag), ID3_V1_LEN_TITLE);
47 io::writeTrailingSpaces(writer, id3::v2::getArtist(tag), ID3_V1_LEN_ARTIST);
48 io::writeTrailingSpaces(writer, id3::v2::getAlbum(tag), ID3_V1_LEN_ALBUM);
49 io::writeTrailingSpaces(writer, id3::v2::getYear(tag), ID3_V1_LEN_YEAR);
50
51 size_t track = id3::v2::getTrackNum(tag);
52 String comment = id3::v2::getV1Comment(tag);
53 if (track > 0)
54 {
55 io::writeTrailingSpaces(writer, comment, ID3_V1_LEN_COMMENT - 2);
56 writer.writeChar('\0');
57 writer.writeChar((char) track);
58 }
59 else
60 {
61 io::writeTrailingSpaces(writer, comment, ID3_V1_LEN_COMMENT);
62 }
63 writer.writeChar((char) id3::v2::getGenreNum(tag));
64}
65
66namespace
67{
68 void renderFrames(ID3_Writer& writer, const ID3_TagImpl& tag)
69 {
70 for (ID3_TagImpl::const_iterator iter = tag.begin(); iter != tag.end(); ++iter)
71 {
72 const ID3_Frame* frame = *iter;
73 if (frame) frame->Render(writer);
74 }
75 }
76}
77
78void id3::v2::render(ID3_Writer& writer, const ID3_TagImpl& tag)
79{
80 // There has to be at least one frame for there to be a tag...
81 if (tag.NumFrames() == 0)
82 {
83 ID3D_WARNING( "id3::v2::render(): no frames to render" );
84 return;
85 }
86
87 ID3D_NOTICE( "id3::v2::render(): rendering" );
88 ID3_TagHeader hdr;
89 hdr.SetSpec(tag.GetSpec());
90 hdr.SetExtended(tag.GetExtended());
92 hdr.SetFooter(tag.GetFooter());
93
94 // set up the encryption and grouping IDs
95
96 // ...
97 String frms;
98 io::StringWriter frmWriter(frms);
99 if (!tag.GetUnsync())
100 {
101 ID3D_NOTICE( "id3::v2::render(): rendering frames" );
102 renderFrames(frmWriter, tag);
103 hdr.SetUnsync(false);
104 }
105 else
106 {
107 ID3D_NOTICE( "id3::v2::render(): rendering unsynced frames" );
108 io::UnsyncedWriter uw(frmWriter);
109 renderFrames(uw, tag);
110 uw.flush();
111 ID3D_NOTICE( "id3::v2::render(): numsyncs = " << uw.getNumSyncs() );
112 hdr.SetUnsync(uw.getNumSyncs() > 0);
113 }
114 size_t frmSize = frms.size();
115 if (frmSize == 0)
116 {
117 ID3D_WARNING( "id3::v2::render(): rendered frame size is 0 bytes" );
118 return;
119 }
120
121 // zero the remainder of the buffer so that our padding bytes are zero
122 luint nPadding = tag.PaddingSize(frmSize);
123 ID3D_NOTICE( "id3::v2::render(): padding size = " << nPadding );
124
125 hdr.SetDataSize(frmSize + tag.GetExtendedBytes() + nPadding);
126
127 hdr.Render(writer);
128
129 writer.writeChars(frms.data(), frms.size());
130
131 for (size_t i = 0; i < nPadding; ++i)
132 {
133 if (writer.writeChar('\0') == ID3_Writer::END_OF_WRITER)
134 {
135 break;
136 }
137 }
138}
139
140#define ID3_PADMULTIPLE (2048)
141#define ID3_PADMAX (4096)
142
143size_t ID3_TagImpl::Size() const
144{
145 if (this->NumFrames() == 0)
146 {
147 return 0;
148 }
149 ID3_TagHeader hdr;
150
151 hdr.SetSpec(this->GetSpec());
152 size_t headerBytes = hdr.Size();
153
154 size_t frameBytes = 0;
155 for (const_iterator cur = _frames.begin(); cur != _frames.end(); ++cur)
156 {
157 if (*cur)
158 {
159 (*cur)->SetSpec(this->GetSpec());
160 frameBytes += (*cur)->Size();
161 }
162 }
163
164 if (!frameBytes)
165 {
166 return 0;
167 }
168
169 // add 30% for sync
170 if (this->GetUnsync())
171 {
172 frameBytes += frameBytes / 3;
173 }
174
175 // ID3_Tag::Render(uchar*) does NOT bounds-check the destination buffer, and
176 // id3::v2::render() always rounds the rendered v2 tag up to the next
177 // ID3_PADMULTIPLE boundary (the padding flag is dropped on the render path,
178 // because the temporary ID3_TagImpl copy built for rendering via
179 // ID3_TagImpl::operator=() does not preserve _is_padded). Size() is the
180 // value callers use to size that buffer ("uchar* b = new uchar[tag.Size()]"),
181 // so it MUST NOT report fewer bytes than Render() will write, or the heap is
182 // overwritten. The previous code computed the padding from the wrong base
183 // (header + frames instead of frames only) and honoured _is_padded, so it
184 // under-reported by at least ID3_TagHeader::SIZE, and by ~ID3_PADMULTIPLE
185 // when padding was switched off. Reproduce the renderer's size calculation
186 // instead, so Size() is always a safe upper bound for Render().
187 size_t dataBytes = ID3_GetDataSize(*this);
188 size_t appendedBytes = this->GetAppendedBytes();
189 size_t wholeFile = frameBytes + dataBytes + appendedBytes + headerBytes;
190 wholeFile = ((wholeFile / ID3_PADMULTIPLE) + 1) * ID3_PADMULTIPLE;
191 size_t tagBytes = wholeFile - dataBytes - appendedBytes;
192
193 // When rewriting a file in place the renderer may instead pad to fill the
194 // existing tag area (see PaddingSize()); never report less than that.
195 size_t prepended = this->GetPrependedBytes();
196 return (tagBytes > prepended) ? tagBytes : prepended;
197}
198
199
201{
202 if (this->GetSpec() == ID3V2_3_0)
203 {
204 }
205
206 return ;
207}
208
209
210
211size_t ID3_TagImpl::PaddingSize(size_t curSize) const
212{
213 luint newSize = 0;
214
215 // if padding is switched off
216 if (! _is_padded)
217 {
218 return 0;
219 }
220
221 // if the old tag was large enough to hold the new tag, then we will simply
222 // pad out the difference - that way the new tag can be written without
223 // shuffling the rest of the song file around
224 if ((this->GetPrependedBytes()-ID3_TagHeader::SIZE > 0) &&
225 (this->GetPrependedBytes()-ID3_TagHeader::SIZE >= curSize) &&
227 {
228 newSize = this->GetPrependedBytes()-ID3_TagHeader::SIZE;
229 }
230 else
231 {
232 luint tempSize = curSize + ID3_GetDataSize(*this) +
234
235 // this method of automatic padding rounds the COMPLETE FILE up to the
236 // nearest 2K. If the file will already be an even multiple of 2K (with
237 // the tag included) then we just add another 2K of padding
238 tempSize = ((tempSize / ID3_PADMULTIPLE) + 1) * ID3_PADMULTIPLE;
239
240 // the size of the new tag is the new filesize minus the audio data
241 newSize = tempSize - ID3_GetDataSize(*this) - this->GetAppendedBytes () -
242 ID3_TagHeader::SIZE;
243 }
244
245 return newSize - curSize;
246}
247
The representative class of an id3v2 frame.
bool SetDataSize(size_t size)
Definition header.h:64
bool SetExperimental(bool b)
Definition header_tag.h:80
void Render(ID3_Writer &) const
bool SetFooter(bool b)
Definition header_tag.h:87
size_t Size() const
bool SetSpec(ID3_V2Spec)
bool SetExtended(bool b)
Definition header_tag.h:73
bool SetUnsync(bool b)
Definition header_tag.h:66
size_t GetAppendedBytes() const
Definition tag_impl.h:112
size_t GetExtendedBytes() const
Definition tag_impl.cpp:278
size_t PaddingSize(size_t) const
bool GetExperimental() const
Definition tag_impl.cpp:268
size_t NumFrames() const
Definition tag_impl.h:121
bool GetUnsync() const
Definition tag_impl.cpp:258
size_t GetPrependedBytes() const
Definition tag_impl.h:111
bool GetExtended() const
Definition tag_impl.cpp:263
iterator begin()
Definition tag_impl.h:132
Frames::const_iterator const_iterator
Definition tag_impl.h:78
void RenderExtHeader(uchar *)
bool GetFooter() const
Definition tag_impl.cpp:273
ID3_V2Spec GetSpec() const
Definition tag_impl.cpp:232
size_t Size() const
iterator end()
Definition tag_impl.h:133
virtual size_type writeChars(const char_type buf[], size_type len)=0
Write up to len characters into buf and advance the internal position accordingly.
virtual int_type writeChar(char_type ch)
Write a single character and advance the internal position.
Definition writer.h:71
static const int_type END_OF_WRITER
Definition writer.h:41
long unsigned int luint
Definition globals.h:123
@ ID3V2_3_0
Definition globals.h:174
unsigned char uchar
Definition globals.h:122
@ ID3_V1_LEN_YEAR
Definition globals.h:344
@ ID3_V1_LEN_ARTIST
Definition globals.h:342
@ ID3_V1_LEN_ALBUM
Definition globals.h:343
@ ID3_V1_LEN_TITLE
Definition globals.h:341
@ ID3_V1_LEN_COMMENT
Definition globals.h:345
void render(ID3_Writer &, const ID3_TagImpl &)
void render(ID3_Writer &writer, const ID3_TagImpl &tag)
size_t ID3_GetDataSize(const ID3_TagImpl &)
Definition tag_impl.cpp:323
#define ID3_PADMAX
#define ID3_PADMULTIPLE