mirror of
https://github.com/cookiengineer/audacity
synced 2025-05-04 17:49:45 +02:00
377 lines
10 KiB
C++
377 lines
10 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"
|
|
|
|
class AutoRollbackRenamer {
|
|
public:
|
|
AutoRollbackRenamer(wxString oldName, wxString newName) {
|
|
mOldName = oldName;
|
|
mNewName = newName;
|
|
mRenameSucceeded = ::wxRenameFile(mOldName, mNewName);
|
|
mFinished = false;
|
|
mNewFile = NULL;
|
|
}
|
|
~AutoRollbackRenamer()
|
|
{
|
|
if (mNewFile)
|
|
fclose(mNewFile);
|
|
|
|
if (mRenameSucceeded && !mFinished) {
|
|
::wxRemoveFile(mOldName);
|
|
::wxRenameFile(mNewName, mOldName);
|
|
}
|
|
}
|
|
bool RenameSucceeded()
|
|
{
|
|
return mRenameSucceeded;
|
|
}
|
|
void Finished()
|
|
{
|
|
mFinished = true;
|
|
}
|
|
void SetNewFile(FILE *f)
|
|
{
|
|
mNewFile = f;
|
|
}
|
|
|
|
wxString mOldName, mNewName;
|
|
bool mRenameSucceeded;
|
|
bool mFinished;
|
|
FILE *mNewFile;
|
|
};
|
|
|
|
static bool ConvertLegacyTrack(wxTextFile *f, XMLFileWriter &xmlFile)
|
|
{
|
|
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);
|
|
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(wxFileName filename)
|
|
{
|
|
wxTextFile f;
|
|
XMLFileWriter xmlFile;
|
|
int index = 0;
|
|
wxString backupName;
|
|
|
|
do {
|
|
index++;
|
|
fflush(stdout);
|
|
backupName = filename.GetPath() + wxFILE_SEP_PATH + filename.GetName() +
|
|
wxT("_bak") + wxString::Format(wxT("%d"), index) + wxT(".") + filename.GetExt();
|
|
} while(::wxFileExists(backupName));
|
|
|
|
// This will move the original file out of the way, but
|
|
// move it back if we exit from this function early.
|
|
AutoRollbackRenamer renamer(filename.GetFullPath(), backupName);
|
|
if (!renamer.RenameSucceeded())
|
|
return false;
|
|
|
|
f.Open(backupName);
|
|
if (!f.IsOpened())
|
|
return false;
|
|
|
|
wxString name = filename.GetFullPath();
|
|
|
|
try
|
|
{
|
|
xmlFile.Open(name, wxT("wb"));
|
|
}
|
|
catch (XMLFileWriterException* pException)
|
|
{
|
|
delete pException;
|
|
return false;
|
|
}
|
|
|
|
renamer.SetNewFile(xmlFile.fp());
|
|
|
|
try
|
|
{
|
|
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();
|
|
}
|
|
|
|
xmlFile.EndTag(wxT("audacityproject"));
|
|
xmlFile.Close();
|
|
}
|
|
catch (XMLFileWriterException* pException)
|
|
{
|
|
// Error writing XML file (e.g. disk full)
|
|
delete pException;
|
|
return false;
|
|
}
|
|
|
|
renamer.Finished();
|
|
|
|
::wxMessageBox(wxString::Format(_("Converted a 1.0 project file to the new format.\nThe old file has been saved as '%s'"), backupName.c_str()),
|
|
_("Opening Audacity Project"));
|
|
|
|
return true;
|
|
}
|