void DirManager::CheckHashTableSize() { // This method makes sure that our hash table doesn't fill up. // When it's about halfway full (i.e. starting to exceed its // capacity), we create a new hash table with double the size, // and copy everything over. if (blockFileHash->GetCount() >= hashTableSize/2) { wxBusyCursor busy; hashTableSize *= 2; wxHashTable *newHash = new wxHashTable(wxKEY_STRING, hashTableSize); blockFileHash->BeginFind(); wxNode *n = blockFileHash->Next(); while(n) { BlockFile *b = (BlockFile *)n->GetData(); newHash->Put(b->GetName(), (wxObject *) b); n = blockFileHash->Next(); } delete blockFileHash; blockFileHash = newHash; } }
void WaveTrack::AppendAlias(wxString fullPath, sampleCount start, sampleCount len, int channel) { WaveBlock *newBlock = new WaveBlock(); newBlock->start = numSamples; newBlock->len = len; newBlock->f = dirManager->NewAliasBlockFile(totalHeaderLen, fullPath, start, len, channel); InitBlock(newBlock); BlockFile *f = newBlock->f; sampleType *buffer = new sampleType[len]; Read(buffer, newBlock, 0, len); wxASSERT(f); bool opened = f->OpenWriting(); wxASSERT(opened); UpdateSummaries(buffer, newBlock, len); f->Close(); delete[]buffer; block->Add(newBlock); numSamples += newBlock->len; envelope.SetTrackLen(numSamples / rate); }
// True = success bool FindDependencies(AudacityProject *project, AliasedFileArray *outAliasedFiles) { sampleFormat format = project->GetDefaultFormat(); BlockArray blocks; GetAllSeqBlocks(project, &blocks); AliasedFileHash aliasedFileHash; BoolBlockFileHash blockFileHash; int i; for(i=0; i<(int)blocks.GetCount(); i++) { BlockFile *f = blocks[i]->f; if (f->IsAlias() && !blockFileHash[f]) { blockFileHash[f] = true; // Don't count the same blockfile twice AliasBlockFile *aliasBlockFile = (AliasBlockFile *)f; wxFileName fileName = aliasBlockFile->GetAliasedFile(); wxString fileNameStr = fileName.GetFullPath(); int blockBytes = (SAMPLE_SIZE(format) * aliasBlockFile->GetLength()); if (aliasedFileHash[fileNameStr]) aliasedFileHash[fileNameStr]->bytes += blockBytes; else { outAliasedFiles->Add(AliasedFile(fileName, blockBytes)); aliasedFileHash[fileNameStr] = &((*outAliasedFiles)[outAliasedFiles->GetCount()-1]); } } } return true; }
void testFileValidity() { // Use libsndfile to read the file. Make sure: // 1. it is correctly recognized as an AU file // 2. it has all the header information we expect std::cout << "\tthe created files should be valid AU files with the expected number of samples..."; std::cout << std::flush; BlockFile *theFiles[] = {int16BlockFile, int24BlockFile, floatBlockFile}; for(int i = 0; i < 3; i++) { BlockFile *bf = theFiles[i]; SF_INFO info; memset(&info, 0, sizeof(info)); SNDFILE *sf = sf_open(bf->GetFileName().GetFullPath(), SFM_READ, &info); assert(sf); assert(info.frames == dataLen); assert(info.channels == 1); assert(info.format & SF_FORMAT_AU); sf_close(sf); } std::cout << "OK\n"; }
bool WaveTrack::InitBlock(WaveBlock * b) { wxASSERT(b); BlockFile *f = b->f; if (!f->OpenWriting()) return false; f->Write(headerTag, headerTagLen); /* * This code shouldn't be needed because UpdateSummaries * always writes exactly what's needed. sampleCount slen = summary64KLen + summary256Len; sampleType *tempSamples = new sampleType[slen]; for(int i=0; i<slen; i++) tempSamples[i] = 0; f->Write((void *)tempSamples, sizeof(sampleType) * slen); delete[] tempSamples; */ f->Close(); return true; }
BlockFile *DirManager::LoadBlockFile(wxTextFile * in, sampleFormat format) { wxASSERT(projFull != ""); long summaryLen; if (!(in->GetNextLine().ToLong(&summaryLen))) return NULL; wxString blockName = in->GetNextLine(); bool alias = false; wxString aliasFullPath; long localLen, start, len, channel; if (blockName == "Alias") { alias = true; aliasFullPath = in->GetNextLine(); //if (!(in->GetNextLine().ToLong(&localLen))) // return NULL; if (!(in->GetNextLine().ToLong(&start))) return NULL; if (!(in->GetNextLine().ToLong(&len))) return NULL; if (!(in->GetNextLine().ToLong(&channel))) return NULL; blockName = in->GetNextLine(); } wxString pathName = projFull + wxFILE_SEP_PATH + blockName; BlockFile *retrieved = (BlockFile *) blockFileHash->Get(blockName); if (retrieved) { wxASSERT(retrieved->IsAlias() == alias); retrieved->Ref(); return retrieved; } else { BlockFile *newBlockFile = new BlockFile(blockName, pathName, summaryLen); if (alias) { newBlockFile->SetAliasedData(aliasFullPath, start, len, channel); aliasList.Add(aliasFullPath); } newBlockFile->mSampleFormat = format; blockFileHash->Put(blockName, (wxObject *) newBlockFile); CheckHashTableSize(); if (!wxFileExists(pathName)) return 0; return newBlockFile; } }
// get the sum of the sizes of all blocks this track list // references. However, if a block is referred to multiple // times it is only counted once. Return value is in bytes. wxLongLong UndoManager::CalculateSpaceUsage(int index) { TrackListOfKindIterator iter(Track::Wave); WaveTrack *wt; WaveClipList::compatibility_iterator it; BlockArray *blocks; unsigned int i; // get a map of all blocks referenced in this TrackList std::map<BlockFile*, wxLongLong> cur; wt = (WaveTrack *) iter.First(stack[index]->tracks); while (wt) { for (it = wt->GetClipIterator(); it; it = it->GetNext()) { blocks = it->GetData()->GetSequenceBlockArray(); for (i = 0; i < blocks->GetCount(); i++) { BlockFile* pBlockFile = blocks->Item(i)->f; if (pBlockFile->GetFileName().FileExists()) cur[pBlockFile] = pBlockFile->GetSpaceUsage(); } } wt = (WaveTrack *) iter.Next(); } if (index > 0) { // get a set of all blocks referenced in all prev TrackList std::set<BlockFile*> prev; while (--index) { wt = (WaveTrack *) iter.First(stack[index]->tracks); while (wt) { for (it = wt->GetClipIterator(); it; it = it->GetNext()) { blocks = it->GetData()->GetSequenceBlockArray(); for (i = 0; i < blocks->GetCount(); i++) { prev.insert(blocks->Item(i)->f); } } wt = (WaveTrack *) iter.Next(); } } // remove all blocks in prevBlockFiles from curBlockFiles std::set<BlockFile*>::const_iterator prevIter; for (prevIter = prev.begin(); prevIter != prev.end(); prevIter++) { cur.erase(*prevIter); } } // sum the sizes of the blocks remaining in curBlockFiles; wxLongLong bytes = 0; std::map<BlockFile*, wxLongLong>::const_iterator curIter; for (curIter = cur.begin(); curIter != cur.end(); curIter++) { bytes += curIter->second; } return bytes; }
void UndoManager::CalculateSpaceUsage() { TIMER_START( "CalculateSpaceUsage", space_calc ); TrackListOfKindIterator iter(Track::Wave); space.Clear(); space.Add(0, stack.GetCount()); Set s1, s2; Set *prev = &s1; Set *cur = &s2; for (size_t i = 0, cnt = stack.GetCount(); i < cnt; i++) { // Swap map pointers std::swap(cur, prev); // And clean out the NEW current map cur->clear(); // Scan all tracks at current level WaveTrack *wt = (WaveTrack *) iter.First(stack[i]->tracks); while (wt) { // Scan all clips within current track WaveClipList::compatibility_iterator it = wt->GetClipIterator(); while (it) { // Scan all blockfiles within current clip BlockArray *blocks = it->GetData()->GetSequenceBlockArray(); for (size_t b = 0, cnt = blocks->size(); b < cnt; b++) { BlockFile *file = (*blocks)[b].f; // Accumulate space used by the file if the file didn't exist // in the previous level if (prev->count(file) == 0 && cur->count(file) == 0) { space[i] += file->GetSpaceUsage().GetValue(); } // Add file to current set cur->insert(file); } it = it->GetNext(); } wt = (WaveTrack *) iter.Next(); } } TIMER_STOP( space_calc ); }
BlockFile *DirManager::LoadBlockFile(wxTextFile * in) { wxASSERT(projFull != ""); wxString blockName = in->GetNextLine(); bool alias = false; wxString aliasFullPath; long localLen, start, len, channel; if (blockName == "Alias") { alias = true; aliasFullPath = in->GetNextLine(); if (!(in->GetNextLine().ToLong(&localLen))) return NULL; if (!(in->GetNextLine().ToLong(&start))) return NULL; if (!(in->GetNextLine().ToLong(&len))) return NULL; if (!(in->GetNextLine().ToLong(&channel))) return NULL; blockName = in->GetNextLine(); } wxString pathName = projFull + pathChar + blockName; BlockFile *retrieved = (BlockFile *) blockFileHash->Get(blockName); if (retrieved) { wxASSERT(retrieved->IsAlias() == alias); retrieved->Ref(); return retrieved; } else { BlockFile *newBlockFile; if (alias) { newBlockFile = new BlockFile(blockName, pathName, localLen, aliasFullPath, start, len, channel); aliasList.Add(aliasFullPath); } else newBlockFile = new BlockFile(blockName, pathName); blockFileHash->Put(blockName, (wxObject *) newBlockFile); CheckHashTableSize(); if (!wxFileExists(pathName)) return 0; return newBlockFile; } }
void WaveTrack::CopyWrite(sampleType * buffer, WaveBlock * b, sampleCount start, sampleCount len) { // Usually we don't write to an existing block; to support Undo, // we copy the old block entirely into memory, dereference it, // make the change, and then write the new block to disk. wxASSERT(b); wxASSERT(b->len <= maxSamples); wxASSERT(start + len <= b->len); dirty++; // forces redraw sampleType *newBuffer = 0; newBuffer = new sampleType[maxSamples]; wxASSERT(newBuffer); Read(newBuffer, b, 0, b->len); for (int i = 0; i < len; i++) newBuffer[start + i] = buffer[i]; BlockFile *oldBlockFile = b->f; b->f = dirManager->NewBlockFile(); bool inited = InitBlock(b); wxASSERT(inited); buffer = newBuffer; start = 0; len = b->len; dirManager->Deref(oldBlockFile); // Write the block BlockFile *f = b->f; wxASSERT(f); bool opened = f->OpenWriting(); wxASSERT(opened); f->SeekTo(totalHeaderLen + (start * sizeof(sampleType))); f->Write((void *) buffer, len * sizeof(sampleType)); UpdateSummaries(buffer, b, len); if (newBuffer) delete[]newBuffer; f->Close(); }
void FaultyBlockFileUnitTest::setUp() { // cout << "FaultyBlockFileUnitTest::setUp()" << endl ; system("rm -f /tmp/newblockfile*") ; // Important. Otherwise state is left between tests. BlockFile *bfp = new BlockFile("/tmp/newblockfile") ; assert(bfp->create(1, 10, 1024)); bf = new FaultyBlockFile(bfp); //tb1 = new Block() ; //tb2 = new Block() ; }
void FindDependencies(AudacityProject *project, AliasedFileArray *outAliasedFiles) { sampleFormat format = project->GetDefaultFormat(); BlockArray blocks; GetAllSeqBlocks(project, &blocks); AliasedFileHash aliasedFileHash; BoolBlockFileHash blockFileHash; int i; for (i = 0; i < (int)blocks.GetCount(); i++) { BlockFile *f = blocks[i]->f; if (f->IsAlias() && (blockFileHash.count(f) == 0)) { // f is an alias block we have not yet counted. blockFileHash[f] = true; // Don't count the same blockfile twice. AliasBlockFile *aliasBlockFile = (AliasBlockFile *)f; wxFileName fileName = aliasBlockFile->GetAliasedFileName(); // In DirManager::ProjectFSCK(), if the user has chosen to // "Replace missing audio with silence", the code there puts in an empty wxFileName. // Don't count those in dependencies. if (!fileName.IsOk()) continue; wxString fileNameStr = fileName.GetFullPath(); int blockBytes = (SAMPLE_SIZE(format) * aliasBlockFile->GetLength()); if (aliasedFileHash.count(fileNameStr) > 0) // Already put this AliasBlockFile in aliasedFileHash. // Update block count. aliasedFileHash[fileNameStr]->mByteCount += blockBytes; else { // Haven't counted this AliasBlockFile yet. // Add to return array and internal hash. outAliasedFiles->Add(AliasedFile(fileName, blockBytes, fileName.FileExists())); aliasedFileHash[fileNameStr] = &((*outAliasedFiles)[outAliasedFiles->GetCount()-1]); } } } }
// // Load // // Load system data // void Load(BlockFile &bFile) { // Get the size of the block U32 size; // Open the data block bFile.OpenBlock(SAVEBLOCK, TRUE, &size); // Expected size of buffer U32 bufferSize = WorldCtrl::CellMapX() * WorldCtrl::CellMapZ(); // Check the block size if (bufferSize == size) { // Get the start of the buffer Game::TeamBitfield *ptr = (Game::TeamBitfield *)(bFile.GetBlockPtr()); // Iterate through each cell for (U32 i = 0; i < bufferSize; ++i) { // Setup the team bits for (U32 team = 0; team < teamCount; team++) { if (Game::TeamTest(*ptr, team)) { seeMap[0][team][0][i] |= SEENMASK; } } // Move to next cell ++ptr; } } else { LOG_WARN(("Sight: Save block was unexpected size (%d/%d)", size, bufferSize)); } // Done bFile.CloseBlock(); // Ensure display gets updated for new data DirtyAllCells(); }
void DirManager::FillBlockfilesCache() { bool cacheBlockFiles = false; gPrefs->Read(wxT("/Directories/CacheBlockFiles"), &cacheBlockFiles); if (!cacheBlockFiles) return; // user opted not to cache block files BlockHash::iterator i; int numNeed = 0; i = blockFileHash.begin(); while (i != blockFileHash.end()) { BlockFile *b = i->second; if (b->GetNeedFillCache()) numNeed++; i++; } if (numNeed == 0) return; AudacityProject *p = GetActiveProject(); p->ProgressShow(_("Caching audio"), _("Caching audio into memory...")); i = blockFileHash.begin(); int current = 0; while (i != blockFileHash.end()) { BlockFile *b = i->second; if (b->GetNeedFillCache()) b->FillCache(); if (!p->ProgressUpdate((int)((current * 1000.0) / numNeed))) break; // user cancelled progress dialog, stop caching i++; current++; } p->ProgressHide(); }
bool Sequence::Read(samplePtr buffer, sampleFormat format, SeqBlock * b, sampleCount start, sampleCount len) const { wxASSERT(b); wxASSERT(start >= 0); wxASSERT(start + len <= b->len); BlockFile *f = b->f; int result = f->ReadData(buffer, format, start, len); if (result != len) { // TODO err printf(_("Expected to read %d samples, got %d samples.\n"), len, result); } return true; }
void WaveTrack::Read64K(sampleType * buffer, WaveBlock * b, sampleCount start, sampleCount len) { wxASSERT(b); wxASSERT(start >= 0); wxASSERT(start + len <= ((b->len + 65535) / 65536)); start *= 2; len *= 2; BlockFile *f = b->f; bool opened = f->OpenReadHeader(); wxASSERT(opened); f->SeekTo(headerTagLen + start * sizeof(sampleType)); int result = f->Read((void *) buffer, (int) (len * sizeof(sampleType))); wxASSERT(result == (int) (len * sizeof(sampleType))); f->Close(); }
bool Sequence::ConvertToSampleFormat(sampleFormat format) { if (format == mSampleFormat) return true; if (mBlock->Count() == 0) { mSampleFormat = format; return true; } sampleFormat oldFormat = mSampleFormat; mSampleFormat = format; for (unsigned int i = 0; i < mBlock->Count(); i++) { BlockFile *oldBlock = mBlock->Item(i)->f; sampleCount len = mBlock->Item(i)->len; if (!oldBlock->IsAlias()) { BlockFile *newBlock = mDirManager->NewBlockFile(mSummary->totalSummaryBytes); samplePtr buffer1 = NewSamples(len, oldFormat); samplePtr buffer2 = NewSamples(len, mSampleFormat); oldBlock->ReadData(buffer1, oldFormat, 0, len); CopySamples(buffer1, oldFormat, buffer2, mSampleFormat, len); newBlock->WriteData(buffer2, mSampleFormat, len); mBlock->Item(i)->f = newBlock; mDirManager->Deref(oldBlock); UpdateSummaries(buffer2, mBlock->Item(i), len); DeleteSamples(buffer2); DeleteSamples(buffer1); } } return true; }
void WaveTrack::FirstWrite(sampleType * buffer, WaveBlock * b, sampleCount len) { wxASSERT(b); wxASSERT(b->len <= maxSamples); dirty++; // forces redraw BlockFile *f = b->f; wxASSERT(f); bool opened = f->OpenWriting(); wxASSERT(opened); f->SeekTo(totalHeaderLen); f->Write((void *) buffer, len * sizeof(sampleType)); UpdateSummaries(buffer, b, len); f->Close(); }
bool Sequence::Read(samplePtr buffer, sampleFormat format, SeqBlock * b, sampleCount start, sampleCount len) const { wxASSERT(b); wxASSERT(start >= 0); wxASSERT(start + len <= b->f->GetLength()); BlockFile *f = b->f; int result = f->ReadData(buffer, format, start, len); if (result != len) { wxLogError(wxT("Expected to read %d samples, got %d samples.\n"), len, result); if (result < 0) result = 0; ClearSamples(buffer, format, result, len-result); } return true; }
bool Sequence::ConvertToSampleFormat(sampleFormat format) { if (format == mSampleFormat) return true; if (mBlock->Count() == 0) { mSampleFormat = format; return true; } sampleFormat oldFormat = mSampleFormat; mSampleFormat = format; for (unsigned int i = 0; i < mBlock->Count(); i++) { SeqBlock *b = mBlock->Item(i); BlockFile *oldBlock = b->f; sampleCount len = b->f->GetLength(); if (!oldBlock->IsAlias()) { BlockFile *newBlock; samplePtr buffer1 = NewSamples(len, oldFormat); samplePtr buffer2 = NewSamples(len, mSampleFormat); oldBlock->ReadData(buffer1, oldFormat, 0, len); CopySamples(buffer1, oldFormat, buffer2, mSampleFormat, len); newBlock = mDirManager->NewSimpleBlockFile(buffer2, len, mSampleFormat); mBlock->Item(i)->f = newBlock; mDirManager->Deref(oldBlock); DeleteSamples(buffer2); DeleteSamples(buffer1); } } return true; }
BlockFile *DirManager::GetBlockFile(wxString &blockName) { wxASSERT(projFull != ""); wxString pathName = projFull + pathChar + blockName; BlockFile *retrieved = (BlockFile *)blockFileHash->Get(blockName); if (retrieved) { retrieved->Ref(); return retrieved; } else { BlockFile *newBlockFile = new BlockFile(blockName, pathName); blockFileHash->Put(blockName, (wxObject *)newBlockFile); CheckHashTableSize(); if (!wxFileExists(pathName)) return 0; return newBlockFile; } }
void DirManager::WriteCacheToDisk() { BlockHash::iterator i; int numNeed = 0; i = blockFileHash.begin(); while (i != blockFileHash.end()) { BlockFile *b = i->second; if (b->GetNeedWriteCacheToDisk()) numNeed++; i++; } if (numNeed == 0) return; AudacityProject *p = GetActiveProject(); p->ProgressShow(_("Saving recorded audio"), _("Saving recorded audio to disk...")); i = blockFileHash.begin(); int current = 0; while (i != blockFileHash.end()) { BlockFile *b = i->second; if (b->GetNeedWriteCacheToDisk()) { b->WriteCacheToDisk(); p->ProgressUpdate((int)((current * 1000.0) / numNeed)); } i++; current++; } p->ProgressHide(); }
void WaveTrack::Read(sampleType * buffer, WaveBlock * b, sampleCount start, sampleCount len) { wxASSERT(b); wxASSERT(start >= 0); wxASSERT(start + len <= b->len); BlockFile *f = b->f; bool opened = f->OpenReadData(); wxASSERT(opened); f->SeekTo(totalHeaderLen + (start * sizeof(sampleType))); int result = f->Read((void *) buffer, (int) (len * sizeof(sampleType))); if (result != (int) (len * sizeof(sampleType))) { printf("Expected to read %d bytes, got %d bytes.\n", len * sizeof(sampleType), result); } wxASSERT(result == (int) (len * sizeof(sampleType))); f->Close(); }
// // Save // // Save system data // void Save(BlockFile &bFile) { // Size of required buffer U32 bufferSize = WorldCtrl::CellMapX() * WorldCtrl::CellMapZ(); // Allocate a buffer Game::TeamBitfield *buffer = new Game::TeamBitfield[bufferSize]; Game::TeamBitfield *ptr = buffer; // Iterate the seen map for (U32 i = 0; i < bufferSize; ++i) { // Clear the data for this cell *ptr = 0; // Now set a bit for each team that has seen this cell for (U32 team = 0; team < teamCount; team++) { if (seeMap[0][team][0][i] & SEENMASK) { Game::TeamSet(*ptr, team); } } // Move to next cell ++ptr; } // Save the buffer to the blockfile bFile.OpenBlock(SAVEBLOCK); bFile.WriteToBlock(buffer, bufferSize * sizeof(Game::TeamBitfield)); bFile.CloseBlock(); // Free up the buffer delete [] buffer; }
bool DirManager::EnsureSafeFilename(wxFileName fName) { // Quick check: If it's not even in our alias list, // then the file name is A-OK. if (aliasList.Index(fName.GetFullPath()) == wxNOT_FOUND) return true; /* i18n-hint: 'old' is part of a filename used when a file is renamed. */ // Figure out what the new name for the existing file would be. /* i18n-hint: e.g. Try to go from "mysong.wav" to "mysong-old1.wav". */ // Keep trying until we find a filename that doesn't exist. wxFileName renamedFile = fName; int i = 0; do { i++; /* i18n-hint: This is the pattern for filenames that are created when a file needs to be backed up to a different name. For example, mysong would become mysong-old1, mysong-old2, etc. */ renamedFile.SetName(wxString::Format(_("%s-old%d"), fName.GetName().c_str(), i)); } while (wxFileExists(renamedFile.GetFullPath())); // Test creating a file by that name to make sure it will // be possible to do the rename wxFile testFile(renamedFile.GetFullPath(), wxFile::write); if (!testFile.IsOpened()) { wxLogSysError(_("Unable to open/create test file"), renamedFile.GetFullPath().c_str()); return false; } // Close the file prior to renaming. testFile.Close(); if (!wxRemoveFile(renamedFile.GetFullPath())) { wxLogSysError(_("Unable to remove '%s'"), renamedFile.GetFullPath().c_str()); return false; } wxPrintf(_("Renamed file: %s\n"), renamedFile.GetFullPath().c_str()); // Go through our block files and see if any indeed point to // the file we're concerned about. If so, point the block file // to the renamed file and when we're done, perform the rename. bool needToRename = false; wxBusyCursor busy; BlockHash::iterator it=blockFileHash.begin(); while(it != blockFileHash.end()) { BlockFile *b = it->second; // don't worry, we don't rely on this cast unless IsAlias is true AliasBlockFile *ab = (AliasBlockFile*)b; if (b->IsAlias() && ab->GetAliasedFile() == fName) { needToRename = true; wxPrintf(_("Changing block %s\n"), b->GetFileName().GetFullName().c_str()); ab->ChangeAliasedFile(renamedFile); } it++; } if (needToRename) { if (!wxRenameFile(fName.GetFullPath(), renamedFile.GetFullPath())) { // ACK!!! The renaming was unsuccessful!!! // (This shouldn't happen, since we tried creating a // file of this name and then deleted it just a // second earlier.) But we'll handle this scenario // just in case!!! // Put things back where they were BlockHash::iterator it=blockFileHash.begin(); while(it != blockFileHash.end()) { BlockFile *b = it->second; AliasBlockFile *ab = (AliasBlockFile*)b; if (b->IsAlias() && ab->GetAliasedFile() == renamedFile) ab->ChangeAliasedFile(fName); it++; } // Print error message and cancel the export wxLogSysError(_("Unable to rename '%s' to '%s'"), fName.GetFullPath().c_str(), renamedFile.GetFullPath().c_str()); return false; } aliasList.Remove(fName.GetFullPath()); aliasList.Add(renamedFile.GetFullPath()); } // Success!!! Either we successfully renamed the file, // or we didn't need to! return true; }
bool DirManager::SetProject(wxString & projPath, wxString & projName, bool create) { wxString oldPath = this->projPath; wxString oldName = this->projName; wxString oldFull = projFull; wxString oldLoc = projFull; if (oldLoc == wxT("")) oldLoc = mytemp; if (projPath == wxT("")) projPath = ::wxGetCwd(); this->projPath = projPath; this->projName = projName; this->projFull = projPath + wxFILE_SEP_PATH + projName; wxString cleanupLoc1=oldLoc; wxString cleanupLoc2=projFull; if (create) { if (!wxDirExists(projFull)) if (!wxMkdir(projFull)) return false; #ifdef __UNIX__ chmod(OSFILENAME(projFull), 0775); #endif } else { #ifndef __WXMAC__ if (!wxDirExists(projFull)) return false; #endif } /* Move all files into this new directory. Files which are "locked" get copied instead of moved. (This happens when we perform a Save As - the files which belonged to the last saved version of the old project must not be moved, otherwise the old project would not be safe. */ AudacityProject *p = GetActiveProject(); if (p) p->ProgressShow(_("Progress"), _("Saving project data files")); int total=blockFileHash.size(); int count=0; BlockHash::iterator i=blockFileHash.begin(); bool success = true; while(i != blockFileHash.end() && success) { BlockFile *b = i->second; if (b->IsLocked()) success = CopyToNewProjectDirectory(b); else{ success = MoveToNewProjectDirectory(b); } if (p) p->ProgressUpdate(int ((count * 1000.0) / total)); i++; count++; } if (!success) { // If the move failed, we try to move/copy as many files // back as possible so that no damage was done. (No sense // in checking for errors this time around - there's nothing // that could be done about it.) // Likely causes: directory was not writeable, disk was full projFull = oldLoc; BlockHash::iterator i=blockFileHash.begin(); while(i != blockFileHash.end()) { BlockFile *b = i->second; MoveToNewProjectDirectory(b); if (count>=0 && p) p->ProgressUpdate(int ((count * 1000.0) / total)); i++; count--; } this->projFull = oldFull; this->projPath = oldPath; this->projName = oldName; if (p) p->ProgressHide(); return false; } if (p) p->ProgressHide(); // Some subtlety; SetProject is used both to move a temp project // into a permanent home as well as just set up path variables when // loading a project; in this latter case, the movement code does // nothing because SetProject is called before there are any // blockfiles. Cleanup code trigger is the same if(blockFileHash.size()>0){ // Clean up after ourselves; look for empty directories in the old // and new project directories. The easiest way to do this is to // recurse depth-first and rmdir every directory seen in old and // new; rmdir will fail on non-empty dirs. wxArrayString dirlist; count=rm_dash_rf_enumerate(cleanupLoc1,dirlist,wxEmptyString,0,1); count+=rm_dash_rf_enumerate(cleanupLoc2,dirlist,wxEmptyString,0,1); if(count) rm_dash_rf_execute(dirlist,count,0,1,_("Cleaning up cache directories")); } return true; }
bool DirManager::HandleXMLTag(const wxChar *tag, const wxChar **attrs) { if( mLoadingTarget == NULL ) return false; BlockFile* pBlockFile = NULL; if( !wxStricmp(tag, wxT("silentblockfile")) ) { // Silent blocks don't actually have a file associated, so // we don't need to worry about the hash table at all *mLoadingTarget = SilentBlockFile::BuildFromXML(*this, attrs); return true; } else if ( !wxStricmp(tag, wxT("simpleblockfile")) ) pBlockFile = SimpleBlockFile::BuildFromXML(*this, attrs); else if( !wxStricmp(tag, wxT("pcmaliasblockfile")) ) pBlockFile = PCMAliasBlockFile::BuildFromXML(*this, attrs); else if( !wxStricmp(tag, wxT("blockfile")) || !wxStricmp(tag, wxT("legacyblockfile")) ) { // Support Audacity version 1.1.1 project files int i=0; bool alias = false; while(attrs[i]) { if (!wxStricmp(attrs[i], wxT("alias"))) { if (wxAtoi(attrs[i+1])==1) alias = true; } i++; if (attrs[i]) i++; } if (alias) pBlockFile = LegacyAliasBlockFile::BuildFromXML(projFull, attrs); else pBlockFile = LegacyBlockFile::BuildFromXML(projFull, attrs, mLoadingBlockLen, mLoadingFormat); } else return false; if ((pBlockFile == NULL) || // Check the length here so we don't have to do it in each BuildFromXML method. ((mMaxSamples > -1) && // is initialized (pBlockFile->GetLength() > mMaxSamples))) { delete pBlockFile; return false; } else *mLoadingTarget = pBlockFile; // // If the block we loaded is already in the hash table, then the // object we just loaded is a duplicate, so we delete it and // return a reference to the existing object instead. // wxString name = (*mLoadingTarget)->GetFileName().GetName(); BlockFile *retrieved = blockFileHash[name]; if (retrieved) { // Lock it in order to delete it safely, i.e. without having // it delete the file, too... (*mLoadingTarget)->Lock(); delete (*mLoadingTarget); Ref(retrieved); // Add one to its reference count *mLoadingTarget = retrieved; return true; } // This is a new object blockFileHash[name]=*mLoadingTarget; // MakeBlockFileName wasn't used so we must add the directory // balancing information BalanceInfoAdd(name); return true; }
bool DirManager::SetProject(wxString & projPath, wxString & projName, bool create) { wxString oldPath = projPath; wxString oldName = projName; wxString oldFull = projFull; wxString oldLoc = projFull; if (oldLoc == "") oldLoc = temp; lastProject = projPath; if (projPath == "") projPath =::wxGetCwd(); this->projPath = projPath; this->projName = projName; this->projFull = projPath + wxFILE_SEP_PATH + projName; if (create) { if (!wxPathExists(projFull)) if (!wxMkdir(projFull)) return false; #ifdef __UNIX__ chmod(projFull, 0775); #endif } else { #ifndef __WXMAC__ if (!wxPathExists(projFull)) return false; #endif } /* Move all files into this new directory. Files which are "locked" get copied instead of moved. (This happens when we perform a Save As - the files which belonged to the last saved version of the old project must not be moved, otherwise the old project would not be safe. */ blockFileHash->BeginFind(); wxNode *n = blockFileHash->Next(); bool success = true; while(n && success) { BlockFile *b = (BlockFile *)n->GetData(); if (b->IsLocked()) success = CopyToNewProjectDirectory(b); else success = MoveToNewProjectDirectory(b); n = blockFileHash->Next(); } if (!success) { // If the move failed, we try to move/copy as many files // back as possible so that no damage was done. (No sense // in checking for errors this time around - there's nothing // that could be done about it.) // Likely causes: directory was not writeable, disk was full projFull = oldLoc; blockFileHash->BeginFind(); wxNode *n = blockFileHash->Next(); while(n) { BlockFile *b = (BlockFile *)n->GetData(); MoveToNewProjectDirectory(b); n = blockFileHash->Next(); } projFull = oldFull; projPath = oldPath; projName = oldName; return false; } return true; }
// Given a project and a list of aliased files that should no // longer be external dependencies (selected by the user), replace // all of those alias block files with disk block files. void RemoveDependencies(AudacityProject *project, AliasedFileArray *aliasedFiles) { DirManager *dirManager = project->GetDirManager(); ProgressDialog *progress = new ProgressDialog(_("Removing Dependencies"), _("Copying audio data into project...")); int updateResult = eProgressSuccess; // Hash aliasedFiles based on their full paths and // count total number of bytes to process. AliasedFileHash aliasedFileHash; wxLongLong totalBytesToProcess = 0; unsigned int i; for (i = 0; i < aliasedFiles->GetCount(); i++) { totalBytesToProcess += aliasedFiles->Item(i).mByteCount; wxString fileNameStr = aliasedFiles->Item(i).mFileName.GetFullPath(); aliasedFileHash[fileNameStr] = &aliasedFiles->Item(i); } BlockArray blocks; GetAllSeqBlocks(project, &blocks); const sampleFormat format = project->GetDefaultFormat(); ReplacedBlockFileHash blockFileHash; wxLongLong completedBytes = 0; for (i = 0; i < blocks.GetCount(); i++) { BlockFile *f = blocks[i]->f; if (f->IsAlias() && (blockFileHash.count(f) == 0)) { // f is an alias block we have not yet processed. AliasBlockFile *aliasBlockFile = (AliasBlockFile *)f; wxFileName fileName = aliasBlockFile->GetAliasedFileName(); wxString fileNameStr = fileName.GetFullPath(); if (aliasedFileHash.count(fileNameStr) == 0) // This aliased file was not selected to be replaced. Skip it. continue; // Convert it from an aliased file to an actual file in the project. unsigned int len = aliasBlockFile->GetLength(); samplePtr buffer = NewSamples(len, format); f->ReadData(buffer, format, 0, len); BlockFile *newBlockFile = dirManager->NewSimpleBlockFile(buffer, len, format); DeleteSamples(buffer); // Update our hash so we know what block files we've done blockFileHash[f] = newBlockFile; // Update the progress bar completedBytes += SAMPLE_SIZE(format) * len; updateResult = progress->Update(completedBytes, totalBytesToProcess); if (updateResult != eProgressSuccess) break; } } // Above, we created a SimpleBlockFile contained in our project // to go with each AliasBlockFile that we wanted to migrate. // However, that didn't actually change any references to these // blockfiles in the Sequences, so we do that next... ReplaceBlockFiles(project, blockFileHash); // Subtract one from reference count of new block files; they're // now all referenced the proper number of times by the Sequences ReplacedBlockFileHash::iterator it; for( it = blockFileHash.begin(); it != blockFileHash.end(); ++it ) { BlockFile *f = it->second; dirManager->Deref(f); } delete progress; }
bool DirManager::EnsureSafeFilename(wxFileName fName) { // Quick check: If it's not even in our alias list, // then the file name is A-OK. #if 0 printf("file name: %s\n", fName.GetFullPath().c_str()); printf("string list:\n"); wxStringListNode *node = aliasList.GetFirst(); while (node) { wxString string = node->GetData(); printf("%s\n", string.c_str()); node = node->GetNext(); } #endif if (!aliasList.Member(fName.GetFullPath())) return true; // If any of the following commands fail, your guess is as // good as mine why. The following error message is the // best we can do - we'll use it if any of the renames, // creates, or deletes fail. wxString errStr = _( "Error: is directory write-protected or disk full?" ); /* i18n-hint: 'old' is part of a filename used when a file is renamed. */ // Figure out what the new name for the existing file would be. /* i18n-hint: e.g. Try to go from "mysong.wav" to "mysong-old1.wav". */ // Keep trying until we find a filename that doesn't exist. wxFileName renamedFile = fName; int i = 0; do { i++; /* i18n-hint: This is the pattern for filenames that are created when a file needs to be backed up to a different name. For example, mysong would become mysong-old1, mysong-old2, etc. */ renamedFile.SetName(wxString::Format(_("%s-old%d"), fName.GetName().c_str(), i)); } while (renamedFile.FileExists()); // Test creating a file by that name to make sure it will // be possible to do the rename wxFile testFile(renamedFile.GetFullPath(), wxFile::write); if (!testFile.IsOpened()) { wxMessageBox(errStr); return false; } if (!wxRemoveFile(renamedFile.GetFullPath())) { wxMessageBox(errStr); return false; } printf(_("Renamed file: %s\n"), (const char *)renamedFile.GetFullPath()); // Go through our block files and see if any indeed point to // the file we're concerned about. If so, point the block file // to the renamed file and when we're done, perform the rename. bool needToRename = false; wxBusyCursor busy; blockFileHash->BeginFind(); wxNode *n = blockFileHash->Next(); while(n) { BlockFile *b = (BlockFile *)n->GetData(); // don't worry, we don't rely on this cast unless IsAlias is true AliasBlockFile *ab = (AliasBlockFile*)b; if (b->IsAlias() && ab->GetAliasedFile() == fName) { needToRename = true; printf(_("Changing block %s\n"), (const char *)b->GetFileName().GetFullName()); ab->ChangeAliasedFile(renamedFile); } n = blockFileHash->Next(); } if (needToRename) { if (!wxRenameFile(fName.GetFullPath(), renamedFile.GetFullPath())) { // ACK!!! The renaming was unsuccessful!!! // (This shouldn't happen, since we tried creating a // file of this name and then deleted it just a // second earlier.) But we'll handle this scenario // just in case!!! // Put things back where they were blockFileHash->BeginFind(); n = blockFileHash->Next(); while(n) { BlockFile *b = (BlockFile *)n->GetData(); AliasBlockFile *ab = (AliasBlockFile*)b; if (b->IsAlias() && ab->GetAliasedFile() == renamedFile) ab->ChangeAliasedFile(fName); n = blockFileHash->Next(); } // Print error message and cancel the export wxMessageBox(errStr); return false; } aliasList.Delete(fName.GetFullPath()); aliasList.Add(renamedFile.GetFullPath()); } // Success!!! Either we successfully renamed the file, // or we didn't need to! return true; }