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 <stdio.h>
00029
#include "writers.h"
00030
#include "io_strings.h"
00031
#include "tag_impl.h"
00032
00033
using namespace dami;
00034
00035
#if !defined HAVE_MKSTEMP
00036
# include <stdio.h>
00037
#endif
00038
00039
#if defined HAVE_UNISTD_H
00040
# include <unistd.h>
00041
#endif
00042
00043
#if defined HAVE_SYS_STAT_H
00044
# include <sys/stat.h>
00045
#endif
00046
00047
#if defined WIN32 && (!defined(WINCE))
00048
# include <windows.h>
00049
static int truncate(
const char *path, size_t length)
00050 {
00051
int result = -1;
00052 HANDLE fh;
00053
00054 fh = ::CreateFile(path,
00055 GENERIC_WRITE | GENERIC_READ,
00056 0,
00057
NULL,
00058 OPEN_EXISTING,
00059 FILE_ATTRIBUTE_NORMAL,
00060
NULL);
00061
00062
if(INVALID_HANDLE_VALUE != fh)
00063 {
00064 SetFilePointer(fh, length, NULL, FILE_BEGIN);
00065 SetEndOfFile(fh);
00066 CloseHandle(fh);
00067 result = 0;
00068 }
00069
00070
return result;
00071 }
00072
00073
00074
# if defined CreateFile
00075
# undef CreateFile
00076
# endif
00077
00078
#elif defined(WINCE)
00079
00080
00081
# include <windows.h>
00082
static int truncate(
const char *path, size_t length)
00083 {
00084
int result = -1;
00085
wchar_t wcTempPath[256];
00086 mbstowcs(wcTempPath,path,255);
00087 HANDLE fh;
00088 fh = ::CreateFile(wcTempPath,
00089 GENERIC_WRITE | GENERIC_READ,
00090 0,
00091
NULL,
00092 OPEN_EXISTING,
00093 FILE_ATTRIBUTE_NORMAL,
00094
NULL);
00095
00096
if (INVALID_HANDLE_VALUE != fh)
00097 {
00098 SetFilePointer(fh, length, NULL, FILE_BEGIN);
00099 SetEndOfFile(fh);
00100 CloseHandle(fh);
00101 result = 0;
00102 }
00103
00104
return result;
00105 }
00106
00107
#elif defined(macintosh)
00108
00109
static int truncate(
const char *path, size_t length)
00110 {
00111
00112
return -1;
00113 }
00114
00115
#endif
00116
00117 size_t
ID3_TagImpl::Link(
const char *fileInfo,
bool parseID3v1,
bool parseLyrics3)
00118 {
00119
flags_t tt =
ID3TT_NONE;
00120
if (parseID3v1)
00121 {
00122 tt |=
ID3TT_ID3V1;
00123 }
00124
if (parseLyrics3)
00125 {
00126 tt |=
ID3TT_LYRICS;
00127 }
00128
return this->
Link(fileInfo, tt);
00129 }
00130
00131 size_t
ID3_TagImpl::Link(
const char *fileInfo, flags_t tag_types)
00132 {
00133 _tags_to_parse.
set(tag_types);
00134
00135
if (
NULL == fileInfo)
00136 {
00137
return 0;
00138 }
00139
00140 _file_name = fileInfo;
00141 _changed =
true;
00142
00143 this->
ParseFile();
00144
00145
return this->
GetPrependedBytes();
00146 }
00147
00148
00149 size_t
ID3_TagImpl::Link(
ID3_Reader &reader, flags_t tag_types)
00150 {
00151 _tags_to_parse.
set(tag_types);
00152
00153 _file_name =
"";
00154 _changed =
true;
00155
00156 this->
ParseReader(reader);
00157
00158
return this->
GetPrependedBytes();
00159 }
00160
00161 size_t
RenderV1ToFile(
ID3_TagImpl& tag, fstream& file)
00162 {
00163
if (!file)
00164 {
00165
return 0;
00166 }
00167
00168
00169
00170
00171
00172
if (
ID3_V1_LEN > tag.
GetFileSize())
00173 {
00174 file.seekp(0, ios::end);
00175 }
00176
else
00177 {
00178
00179
00180 file.seekg(0-
ID3_V1_LEN, ios::end);
00181
char sID[
ID3_V1_LEN_ID];
00182
00183
00184 file.read(sID,
ID3_V1_LEN_ID);
00185
00186
00187
00188
if (memcmp(sID,
"TAG",
ID3_V1_LEN_ID) == 0)
00189 {
00190 file.seekp(0-
ID3_V1_LEN, ios::end);
00191 }
00192
00193
00194
else
00195 {
00196 file.seekp(0, ios::end);
00197 }
00198 }
00199
00200
ID3_IOStreamWriter out(file);
00201
00202 id3::v1::render(out, tag);
00203
00204
return ID3_V1_LEN;
00205 }
00206
00207 size_t
RenderV2ToFile(
const ID3_TagImpl& tag, fstream& file)
00208 {
00209 ID3D_NOTICE(
"RenderV2ToFile: starting" );
00210
if (!file)
00211 {
00212 ID3D_WARNING(
"RenderV2ToFile: error in file" );
00213
return 0;
00214 }
00215
00216 String tagString;
00217
io::StringWriter writer(tagString);
00218 id3::v2::render(writer, tag);
00219 ID3D_NOTICE(
"RenderV2ToFile: rendered v2" );
00220
00221
const char* tagData = tagString.data();
00222 size_t tagSize = tagString.size();
00223
00224
00225
if ((!tag.
GetPrependedBytes() && !
ID3_GetDataSize(tag)) ||
00226 (tagSize == tag.
GetPrependedBytes()))
00227 {
00228 file.seekp(0, ios::beg);
00229 file.write(tagData, tagSize);
00230 }
00231
else
00232 {
00233 String filename = tag.
GetFileName();
00234 String sTmpSuffix =
".XXXXXX";
00235
if (filename.size() + sTmpSuffix.size() > ID3_PATH_LENGTH)
00236 {
00237
00238
return 0;
00239
00240 }
00241
char sTempFile[ID3_PATH_LENGTH];
00242 strcpy(sTempFile, filename.c_str());
00243 strcat(sTempFile, sTmpSuffix.c_str());
00244
00245
#if ((defined(__GNUC__) && __GNUC__ >= 3 ) || !defined(HAVE_MKSTEMP))
00246
00247 fstream tmpOut;
00248 createFile(sTempFile, tmpOut);
00249
00250 tmpOut.write(tagData, tagSize);
00251 file.seekg(tag.
GetPrependedBytes(), ios::beg);
00252
char *tmpBuffer[BUFSIZ];
00253
while (!file.eof())
00254 {
00255 file.read((
char *)tmpBuffer, BUFSIZ);
00256 size_t nBytes = file.gcount();
00257 tmpOut.write((
char *)tmpBuffer, nBytes);
00258 }
00259
00260
#else //((defined(__GNUC__) && __GNUC__ >= 3 ) || !defined(HAVE_MKSTEMP))
00261
00262
00263
00264
00265
00266
int fd = mkstemp(sTempFile);
00267
if (fd < 0)
00268 {
00269 remove(sTempFile);
00270
00271 }
00272
00273 ofstream tmpOut(fd);
00274
if (!tmpOut)
00275 {
00276 tmpOut.close();
00277 remove(sTempFile);
00278
return 0;
00279
00280
00281 }
00282
00283 tmpOut.write(tagData, tagSize);
00284 file.seekg(tag.
GetPrependedBytes(), ios::beg);
00285
uchar tmpBuffer[BUFSIZ];
00286
while (file)
00287 {
00288 file.read(tmpBuffer, BUFSIZ);
00289 size_t nBytes = file.gcount();
00290 tmpOut.write(tmpBuffer, nBytes);
00291 }
00292
00293 close(fd);
00294
00295
#endif
00296
00297
tmpOut.close();
00298 file.close();
00299
00300
00301
00302
#if defined(HAVE_SYS_STAT_H)
00303
struct stat fileStat;
00304
if(stat(filename.c_str(), &fileStat) == 0)
00305 {
00306
#endif //defined(HAVE_SYS_STAT_H)
00307
remove(filename.c_str());
00308 rename(sTempFile, filename.c_str());
00309
#if defined(HAVE_SYS_STAT_H)
00310
chmod(filename.c_str(), fileStat.st_mode);
00311 }
00312
#endif //defined(HAVE_SYS_STAT_H)
00313
00314
00315 file.clear();
00316 openWritableFile(filename, file);
00317 }
00318
00319
return tagSize;
00320 }
00321
00322
00323 flags_t ID3_TagImpl::Update(flags_t ulTagFlag)
00324 {
00325
flags_t tags =
ID3TT_NONE;
00326
00327 fstream file;
00328 String filename = this->
GetFileName();
00329
ID3_Err err = openWritableFile(filename, file);
00330 _file_size = getFileSize(file);
00331
00332
if (err ==
ID3E_NoFile)
00333 {
00334 err = createFile(filename, file);
00335 }
00336
if (err ==
ID3E_ReadOnly)
00337 {
00338
return tags;
00339 }
00340
00341
if ((ulTagFlag &
ID3TT_ID3V2) && this->
HasChanged())
00342 {
00343 _prepended_bytes =
RenderV2ToFile(*
this, file);
00344
if (_prepended_bytes)
00345 {
00346 tags |=
ID3TT_ID3V2;
00347 }
00348 }
00349
00350
if ((ulTagFlag &
ID3TT_ID3V1) &&
00351 (!this->
HasTagType(
ID3TT_ID3V1) || this->
HasChanged()))
00352 {
00353 size_t tag_bytes =
RenderV1ToFile(*
this, file);
00354
if (tag_bytes)
00355 {
00356
00357
if (! _file_tags.
test(
ID3TT_ID3V1))
00358 {
00359 _appended_bytes += tag_bytes;
00360 }
00361 tags |=
ID3TT_ID3V1;
00362 }
00363 }
00364 _changed =
false;
00365 _file_tags.
add(tags);
00366 _file_size = getFileSize(file);
00367 file.close();
00368
return tags;
00369 }
00370
00371 flags_t ID3_TagImpl::Strip(flags_t ulTagFlag)
00372 {
00373
flags_t ulTags =
ID3TT_NONE;
00374
const size_t data_size =
ID3_GetDataSize(*
this);
00375
00376
00377
if (ulTagFlag &
ID3TT_PREPENDED & _file_tags.
get())
00378 {
00379 fstream file;
00380
if (
ID3E_NoError != openWritableFile(this->GetFileName(), file))
00381 {
00382
return ulTags;
00383 }
00384 _file_size = getFileSize(file);
00385
00386
00387
00388
00389
00390 file.seekg(this->GetPrependedBytes(), ios::beg);
00391
00392
uchar aucBuffer[BUFSIZ];
00393
00394
00395 size_t nBytesToCopy = data_size;
00396
00397
00398
00399
if (!(ulTagFlag &
ID3TT_APPENDED))
00400 {
00401 nBytesToCopy += this->
GetAppendedBytes();
00402 }
00403
00404
00405
00406
00407
00408 size_t nBytesRemaining = nBytesToCopy,
00409 nBytesCopied = 0;
00410
while (!file.eof())
00411 {
00412
#if (defined(__GNUC__) && __GNUC__ == 2)
00413
size_t nBytesToRead = (size_t)
dami::min((
unsigned int)(nBytesRemaining - nBytesCopied), (
unsigned int)BUFSIZ);
00414
#else
00415
size_t nBytesToRead =
min((
unsigned int)(nBytesRemaining - nBytesCopied), (
unsigned int)BUFSIZ);
00416
#endif
00417
file.read((
char *)aucBuffer, nBytesToRead);
00418 size_t nBytesRead = file.gcount();
00419
00420
if (nBytesRead != nBytesToRead)
00421 {
00422
00423
00424
00425 }
00426
if (nBytesRead > 0)
00427 {
00428
long offset = nBytesRead + this->
GetPrependedBytes();
00429 file.seekp(-offset, ios::cur);
00430 file.write((
char *)aucBuffer, nBytesRead);
00431 file.seekg(this->GetPrependedBytes(), ios::cur);
00432 nBytesCopied += nBytesRead;
00433 }
00434
00435
if (nBytesCopied == nBytesToCopy || nBytesToRead < BUFSIZ)
00436 {
00437
break;
00438 }
00439 }
00440 file.close();
00441 }
00442
00443 size_t nNewFileSize = data_size;
00444
00445
if ((_file_tags.
get() &
ID3TT_APPENDED) && (ulTagFlag &
ID3TT_APPENDED))
00446 {
00447 ulTags |= _file_tags.
get() &
ID3TT_APPENDED;
00448 }
00449
else
00450 {
00451
00452
00453 nNewFileSize += this->
GetAppendedBytes();
00454 }
00455
00456
if ((ulTagFlag &
ID3TT_PREPENDED) && (_file_tags.
get() &
ID3TT_PREPENDED))
00457 {
00458
00459
00460 ulTags |= _file_tags.
get() &
ID3TT_PREPENDED;
00461 }
00462
else
00463 {
00464
00465
00466
00467 nNewFileSize += this->
GetPrependedBytes();
00468 }
00469
00470
if (ulTags && (truncate(_file_name.c_str(), nNewFileSize) == -1))
00471 {
00472
00473
return 0;
00474
00475 }
00476
00477 _prepended_bytes = (ulTags &
ID3TT_PREPENDED) ? 0 : _prepended_bytes;
00478 _appended_bytes = (ulTags &
ID3TT_APPENDED) ? 0 : _appended_bytes;
00479 _file_size = data_size + _prepended_bytes + _appended_bytes;
00480
00481 _changed = _file_tags.
remove(ulTags) || _changed;
00482
00483
return ulTags;
00484 }
00485