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(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
00261
00262
00263
00264
00265
00266 int fd = mkstemp(sTempFile);
00267 if (fd < 0)
00268 {
00269 remove(sTempFile);
00270
00271 }
00272
00273 ofstream tmpOut(sTempFile);
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((char *)tmpBuffer, BUFSIZ);
00289 size_t nBytes = file.gcount();
00290 tmpOut.write((char *)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