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