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 #endif
00294
00295 tmpOut.close();
00296 file.close();
00297
00298
00299
00300 #if defined(HAVE_SYS_STAT_H)
00301 struct stat fileStat;
00302 if(stat(filename.c_str(), &fileStat) == 0)
00303 {
00304 #endif //defined(HAVE_SYS_STAT_H)
00305 remove(filename.c_str());
00306 rename(sTempFile, filename.c_str());
00307 #if defined(HAVE_SYS_STAT_H)
00308 chmod(filename.c_str(), fileStat.st_mode);
00309 }
00310 #endif //defined(HAVE_SYS_STAT_H)
00311
00312
00313 file.clear();
00314 openWritableFile(filename, file);
00315 }
00316
00317 return tagSize;
00318 }
00319
00320
00321 flags_t ID3_TagImpl::Update(flags_t ulTagFlag)
00322 {
00323 flags_t tags = ID3TT_NONE;
00324
00325 fstream file;
00326 String filename = this->GetFileName();
00327 ID3_Err err = openWritableFile(filename, file);
00328 _file_size = getFileSize(file);
00329
00330 if (err == ID3E_NoFile)
00331 {
00332 err = createFile(filename, file);
00333 }
00334 if (err == ID3E_ReadOnly)
00335 {
00336 return tags;
00337 }
00338
00339 if ((ulTagFlag & ID3TT_ID3V2) && this->HasChanged())
00340 {
00341 _prepended_bytes = RenderV2ToFile(*this, file);
00342 if (_prepended_bytes)
00343 {
00344 tags |= ID3TT_ID3V2;
00345 }
00346 }
00347
00348 if ((ulTagFlag & ID3TT_ID3V1) &&
00349 (!this->HasTagType(ID3TT_ID3V1) || this->HasChanged()))
00350 {
00351 size_t tag_bytes = RenderV1ToFile(*this, file);
00352 if (tag_bytes)
00353 {
00354
00355 if (! _file_tags.test(ID3TT_ID3V1))
00356 {
00357 _appended_bytes += tag_bytes;
00358 }
00359 tags |= ID3TT_ID3V1;
00360 }
00361 }
00362 _changed = false;
00363 _file_tags.add(tags);
00364 _file_size = getFileSize(file);
00365 file.close();
00366 return tags;
00367 }
00368
00369 flags_t ID3_TagImpl::Strip(flags_t ulTagFlag)
00370 {
00371 flags_t ulTags = ID3TT_NONE;
00372 const size_t data_size = ID3_GetDataSize(*this);
00373
00374
00375 if (ulTagFlag & ID3TT_PREPENDED & _file_tags.get())
00376 {
00377 fstream file;
00378 if (ID3E_NoError != openWritableFile(this->GetFileName(), file))
00379 {
00380 return ulTags;
00381 }
00382 _file_size = getFileSize(file);
00383
00384
00385
00386
00387
00388 file.seekg(this->GetPrependedBytes(), ios::beg);
00389
00390 uchar aucBuffer[BUFSIZ];
00391
00392
00393 size_t nBytesToCopy = data_size;
00394
00395
00396
00397 if (!(ulTagFlag & ID3TT_APPENDED))
00398 {
00399 nBytesToCopy += this->GetAppendedBytes();
00400 }
00401
00402
00403
00404
00405
00406 size_t
00407 nBytesRemaining = nBytesToCopy,
00408 nBytesCopied = 0;
00409 while (!file.eof())
00410 {
00411 #if (defined(__GNUC__) && __GNUC__ == 2)
00412 size_t nBytesToRead = (size_t)dami::min((unsigned int)(nBytesRemaining - nBytesCopied), (unsigned int)BUFSIZ);
00413 #else
00414 size_t nBytesToRead = min((unsigned int)(nBytesRemaining - nBytesCopied), (unsigned int)BUFSIZ);
00415 #endif
00416 file.read((char *)aucBuffer, nBytesToRead);
00417 size_t nBytesRead = file.gcount();
00418
00419 if (nBytesRead != nBytesToRead)
00420 {
00421
00422
00423
00424 }
00425 if (nBytesRead > 0)
00426 {
00427 long offset = nBytesRead + this->GetPrependedBytes();
00428 file.seekp(-offset, ios::cur);
00429 file.write((char *)aucBuffer, nBytesRead);
00430 file.seekg(this->GetPrependedBytes(), ios::cur);
00431 nBytesCopied += nBytesRead;
00432 }
00433
00434 if (nBytesCopied == nBytesToCopy || nBytesToRead < BUFSIZ)
00435 {
00436 break;
00437 }
00438 }
00439 file.close();
00440 }
00441
00442 size_t nNewFileSize = data_size;
00443
00444 if ((_file_tags.get() & ID3TT_APPENDED) && (ulTagFlag & ID3TT_APPENDED))
00445 {
00446 ulTags |= _file_tags.get() & ID3TT_APPENDED;
00447 }
00448 else
00449 {
00450
00451
00452 nNewFileSize += this->GetAppendedBytes();
00453 }
00454
00455 if ((ulTagFlag & ID3TT_PREPENDED) && (_file_tags.get() & ID3TT_PREPENDED))
00456 {
00457
00458
00459 ulTags |= _file_tags.get() & ID3TT_PREPENDED;
00460 }
00461 else
00462 {
00463
00464
00465
00466 nNewFileSize += this->GetPrependedBytes();
00467 }
00468
00469 if (ulTags && (truncate(_file_name.c_str(), nNewFileSize) == -1))
00470 {
00471
00472 return 0;
00473
00474 }
00475
00476 _prepended_bytes = (ulTags & ID3TT_PREPENDED) ? 0 : _prepended_bytes;
00477 _appended_bytes = (ulTags & ID3TT_APPENDED) ? 0 : _appended_bytes;
00478 _file_size = data_size + _prepended_bytes + _appended_bytes;
00479
00480 _changed = _file_tags.remove(ulTags) || _changed;
00481
00482 return ulTags;
00483 }
00484