mirror of
https://github.com/cookiengineer/audacity
synced 2025-06-19 17:40:15 +02:00
... Strong, meaning that the file at the specified path is created or modified only if all write operations complete without exceptions, barring one very unlikely possibility that a final file rename fails, but even in that case the output is successfully written to some path. This commit does not add throws, but changes the type thrown to a subclass of AudacityException, so that GuardedCall will cause the user to see an error dialog in all cases. Duplicated logic for making temporary files and backups is now all in one place, the class XMLWriter. There may be more new GuardedCalls than necessary -- the catch-all for the event loop, AudacityApp::OnExceptionInMainLoop, might be trusted instead in some cases -- but they are sufficient.
310 lines
8.6 KiB
C++
310 lines
8.6 KiB
C++
/**********************************************************************
|
|
|
|
Audacity: A Digital Audio Editor
|
|
|
|
Legacy.cpp
|
|
|
|
Dominic Mazzoni
|
|
|
|
*******************************************************************//*!
|
|
|
|
\file Legacy.cpp
|
|
\brief Converts old Audacity file types. Implements
|
|
AutoRollbackRenamer.
|
|
|
|
These routines convert Audacity project files from the
|
|
0.98...1.0 format into an XML format that's compatible with
|
|
Audacity 1.2.0 and newer.
|
|
|
|
*//****************************************************************//**
|
|
|
|
\class AutoRollbackRenamer
|
|
\brief AutoRollbackRenamer handles the renaming of files
|
|
which is needed when producing a NEW version of a file which may fail.
|
|
On failure the old version is put back in place.
|
|
|
|
*//*******************************************************************/
|
|
|
|
|
|
#include "Audacity.h"
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include <wx/defs.h>
|
|
#include <wx/ffile.h>
|
|
#include <wx/filefn.h>
|
|
#include <wx/intl.h>
|
|
#include <wx/msgdlg.h>
|
|
#include <wx/string.h>
|
|
#include <wx/textfile.h>
|
|
|
|
#include "Internat.h"
|
|
#include "Legacy.h"
|
|
#include "xml/XMLWriter.h"
|
|
|
|
static bool ConvertLegacyTrack(wxTextFile *f, XMLFileWriter &xmlFile)
|
|
// may throw
|
|
{
|
|
wxString line;
|
|
wxString kind;
|
|
|
|
kind = (*f)[f->GetCurrentLine()];
|
|
|
|
if (kind == wxT("WaveTrack")) {
|
|
xmlFile.StartTag(wxT("wavetrack"));
|
|
xmlFile.WriteAttr(wxT("name"), f->GetNextLine());
|
|
|
|
wxString channel = f->GetNextLine();
|
|
if (channel == wxT("left")) {
|
|
xmlFile.WriteAttr(wxT("channel"), 0);
|
|
line = f->GetNextLine();
|
|
}
|
|
else if (channel == wxT("right")) {
|
|
xmlFile.WriteAttr(wxT("channel"), 1);
|
|
line = f->GetNextLine();
|
|
}
|
|
else if (channel == wxT("mono")) {
|
|
xmlFile.WriteAttr(wxT("channel"), 2);
|
|
line = f->GetNextLine();
|
|
}
|
|
else {
|
|
xmlFile.WriteAttr(wxT("channel"), 2);
|
|
line = channel;
|
|
}
|
|
|
|
if (line == wxT("linked")) {
|
|
xmlFile.WriteAttr(wxT("linked"), 1);
|
|
line = f->GetNextLine();
|
|
}
|
|
|
|
if (line != wxT("offset"))
|
|
return false;
|
|
xmlFile.WriteAttr(wxT("offset"), f->GetNextLine());
|
|
|
|
long envLen;
|
|
|
|
if (f->GetNextLine() != wxT("EnvNumPoints"))
|
|
return false;
|
|
line = f->GetNextLine();
|
|
line.ToLong(&envLen);
|
|
if (envLen < 0 || envLen > 10000)
|
|
return false;
|
|
|
|
size_t envStart = f->GetCurrentLine();
|
|
if (f->GetLineCount() < envStart+(2*envLen)+1)
|
|
return false;
|
|
|
|
f->GoToLine(envStart+(2*envLen));
|
|
if (f->GetNextLine() != wxT("EnvEnd"))
|
|
return false;
|
|
if (f->GetNextLine() != wxT("numSamples"))
|
|
return false;
|
|
|
|
wxString numSamples = f->GetNextLine();
|
|
|
|
if (f->GetNextLine() != wxT("rate"))
|
|
return false;
|
|
|
|
xmlFile.WriteAttr(wxT("rate"), f->GetNextLine());
|
|
|
|
if (envLen > 0) {
|
|
xmlFile.StartTag(wxT("envelope"));
|
|
xmlFile.WriteAttr(wxT("numpoints"), envLen);
|
|
|
|
long i;
|
|
for(i=0; i<envLen; i++) {
|
|
xmlFile.StartTag(wxT("controlpoint"));
|
|
xmlFile.WriteAttr(wxT("t"), f->GetLine(envStart + 2*i + 1));
|
|
xmlFile.WriteAttr(wxT("val"), f->GetLine(envStart + 2*i + 2));
|
|
xmlFile.EndTag(wxT("controlpoint"));
|
|
}
|
|
|
|
xmlFile.EndTag(wxT("envelope"));
|
|
}
|
|
|
|
if (f->GetNextLine() != wxT("numBlocks"))
|
|
return false;
|
|
long numBlocks;
|
|
line = f->GetNextLine();
|
|
line.ToLong(&numBlocks);
|
|
|
|
if (numBlocks < 0 || numBlocks > 131072)
|
|
return false;
|
|
|
|
xmlFile.StartTag(wxT("sequence"));
|
|
xmlFile.WriteAttr(wxT("maxsamples"), 524288);
|
|
xmlFile.WriteAttr(wxT("sampleformat"), 131073);
|
|
xmlFile.WriteAttr(wxT("numsamples"), numSamples);
|
|
|
|
long b;
|
|
for(b=0; b<numBlocks; b++) {
|
|
wxString start;
|
|
wxString len;
|
|
wxString name;
|
|
|
|
if (f->GetNextLine() != wxT("Block start"))
|
|
return false;
|
|
start = f->GetNextLine();
|
|
if (f->GetNextLine() != wxT("Block len"))
|
|
return false;
|
|
len = f->GetNextLine();
|
|
if (f->GetNextLine() != wxT("Block info"))
|
|
return false;
|
|
name = f->GetNextLine();
|
|
|
|
xmlFile.StartTag(wxT("waveblock"));
|
|
xmlFile.WriteAttr(wxT("start"), start);
|
|
|
|
xmlFile.StartTag(wxT("legacyblockfile"));
|
|
if (name == wxT("Alias")) {
|
|
wxString aliasPath = f->GetNextLine();
|
|
wxString localLen = f->GetNextLine();
|
|
wxString aliasStart = f->GetNextLine();
|
|
wxString aliasLen = f->GetNextLine();
|
|
wxString aliasChannel = f->GetNextLine();
|
|
wxString localName = f->GetNextLine();
|
|
|
|
xmlFile.WriteAttr(wxT("name"), localName);
|
|
xmlFile.WriteAttr(wxT("alias"), 1);
|
|
xmlFile.WriteAttr(wxT("aliaspath"), aliasPath);
|
|
|
|
// This was written but not read again?
|
|
xmlFile.WriteAttr(wxT("aliasstart"), aliasStart);
|
|
|
|
xmlFile.WriteAttr(wxT("aliaslen"), aliasLen);
|
|
xmlFile.WriteAttr(wxT("aliaschannel"), aliasChannel);
|
|
xmlFile.WriteAttr(wxT("summarylen"), localLen);
|
|
xmlFile.WriteAttr(wxT("norms"), 1);
|
|
}
|
|
else {
|
|
xmlFile.WriteAttr(wxT("name"), name);
|
|
xmlFile.WriteAttr(wxT("len"), len);
|
|
xmlFile.WriteAttr(wxT("summarylen"), 8244);
|
|
xmlFile.WriteAttr(wxT("norms"), 1);
|
|
}
|
|
xmlFile.EndTag(wxT("legacyblockfile"));
|
|
|
|
xmlFile.EndTag(wxT("waveblock"));
|
|
}
|
|
|
|
xmlFile.EndTag(wxT("sequence"));
|
|
xmlFile.EndTag(wxT("wavetrack"));
|
|
|
|
return true;
|
|
}
|
|
else if (kind == wxT("LabelTrack")) {
|
|
line = f->GetNextLine();
|
|
if (line != wxT("NumMLabels"))
|
|
return false;
|
|
|
|
long numLabels, l;
|
|
|
|
line = f->GetNextLine();
|
|
line.ToLong(&numLabels);
|
|
if (numLabels < 0 || numLabels > 1000000)
|
|
return false;
|
|
|
|
xmlFile.StartTag(wxT("labeltrack"));
|
|
xmlFile.WriteAttr(wxT("name"), wxT("Labels"));
|
|
xmlFile.WriteAttr(wxT("numlabels"), numLabels);
|
|
|
|
for(l=0; l<numLabels; l++) {
|
|
wxString t, title;
|
|
|
|
t = f->GetNextLine();
|
|
title = f->GetNextLine();
|
|
|
|
xmlFile.StartTag(wxT("label"));
|
|
xmlFile.WriteAttr(wxT("t"), t);
|
|
xmlFile.WriteAttr(wxT("title"), title);
|
|
xmlFile.EndTag(wxT("label"));
|
|
}
|
|
|
|
xmlFile.EndTag(wxT("labeltrack"));
|
|
|
|
line = f->GetNextLine();
|
|
if (line != wxT("MLabelsEnd"))
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
else if (kind == wxT("NoteTrack")) {
|
|
// Just skip over it - they didn't even work in version 1.0!
|
|
|
|
do {
|
|
line = f->GetNextLine();
|
|
if (line == wxT("WaveTrack") ||
|
|
line == wxT("NoteTrack") ||
|
|
line == wxT("LabelTrack") ||
|
|
line == wxT("EndTracks")) {
|
|
f->GoToLine(f->GetCurrentLine()-1);
|
|
return true;
|
|
}
|
|
} while (f->GetCurrentLine() < f->GetLineCount());
|
|
|
|
return false;
|
|
}
|
|
else
|
|
return false;
|
|
}
|
|
|
|
bool ConvertLegacyProjectFile(const wxFileName &filename)
|
|
{
|
|
wxTextFile f;
|
|
|
|
const wxString name = filename.GetFullPath();
|
|
f.Open( name );
|
|
if (!f.IsOpened())
|
|
return false;
|
|
|
|
return GuardedCall< bool >( [&] {
|
|
XMLFileWriter xmlFile{ name, _("Error Converting Legacy Project File") };
|
|
|
|
xmlFile.Write(wxT("<?xml version=\"1.0\"?>\n"));
|
|
|
|
wxString label;
|
|
wxString value;
|
|
|
|
if (f.GetFirstLine() != wxT("AudacityProject"))
|
|
return false;
|
|
if (f.GetNextLine() != wxT("Version"))
|
|
return false;
|
|
if (f.GetNextLine() != wxT("0.95"))
|
|
return false;
|
|
if (f.GetNextLine() != wxT("projName"))
|
|
return false;
|
|
|
|
xmlFile.StartTag(wxT("audacityproject"));
|
|
xmlFile.WriteAttr(wxT("projname"), f.GetNextLine());
|
|
xmlFile.WriteAttr(wxT("version"), wxT("1.1.0"));
|
|
xmlFile.WriteAttr(wxT("audacityversion"),AUDACITY_VERSION_STRING);
|
|
|
|
label = f.GetNextLine();
|
|
while (label != wxT("BeginTracks")) {
|
|
xmlFile.WriteAttr(label, f.GetNextLine());
|
|
label = f.GetNextLine();
|
|
}
|
|
|
|
label = f.GetNextLine();
|
|
while (label != wxT("EndTracks")) {
|
|
bool success = ConvertLegacyTrack(&f, xmlFile);
|
|
if (!success)
|
|
return false;
|
|
label = f.GetNextLine();
|
|
}
|
|
|
|
// Close original before Commit() tries to overwrite it.
|
|
f.Close();
|
|
|
|
xmlFile.EndTag(wxT("audacityproject"));
|
|
xmlFile.Commit();
|
|
|
|
::wxMessageBox(wxString::Format(_("Converted a 1.0 project file to the new format.\nThe old file has been saved as '%s'"), xmlFile.GetBackupName().c_str()),
|
|
_("Opening Audacity Project"));
|
|
|
|
return true;
|
|
} );
|
|
}
|