1 /**********************************************************************
2 
3   Audacity: A Digital Audio Editor
4 
5   Legacy.cpp
6 
7   Dominic Mazzoni
8 
9 *******************************************************************//*!
10 
11 \file Legacy.cpp
12 \brief Converts old Audacity file types.  Implements
13 AutoRollbackRenamer.
14 
15   These routines convert Audacity project files from the
16   0.98...1.0 format into an XML format that's compatible with
17   Audacity 1.2.0 and newer.
18 
19 *//****************************************************************//**
20 
21 \class AutoRollbackRenamer
22 \brief AutoRollbackRenamer handles the renaming of files
23 which is needed when producing a NEW version of a file which may fail.
24 On failure the old version is put back in place.
25 
26 *//*******************************************************************/
27 
28 
29 
30 #include "Legacy.h"
31 
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 
36 #include <wx/defs.h>
37 #include <wx/ffile.h>
38 #include <wx/filefn.h>
39 #include <wx/intl.h>
40 #include <wx/string.h>
41 #include <wx/textfile.h>
42 
43 #include "widgets/AudacityMessageBox.h"
44 #include "XMLWriter.h"
45 
ConvertLegacyTrack(wxTextFile * f,XMLFileWriter & xmlFile)46 static bool ConvertLegacyTrack(wxTextFile *f, XMLFileWriter &xmlFile)
47 // may throw
48 {
49    wxString line;
50    wxString kind;
51 
52    kind = (*f)[f->GetCurrentLine()];
53 
54    if (kind == wxT("WaveTrack")) {
55       xmlFile.StartTag(wxT("wavetrack"));
56       xmlFile.WriteAttr(wxT("name"), f->GetNextLine());
57 
58       wxString channel = f->GetNextLine();
59       if (channel == wxT("left")) {
60          xmlFile.WriteAttr(wxT("channel"), 0);
61          line = f->GetNextLine();
62       }
63       else if (channel == wxT("right")) {
64          xmlFile.WriteAttr(wxT("channel"), 1);
65          line = f->GetNextLine();
66       }
67       else if (channel == wxT("mono")) {
68          xmlFile.WriteAttr(wxT("channel"), 2);
69          line = f->GetNextLine();
70       }
71       else {
72          xmlFile.WriteAttr(wxT("channel"), 2);
73          line = channel;
74       }
75 
76       if (line == wxT("linked")) {
77          xmlFile.WriteAttr(wxT("linked"), 1);
78          line = f->GetNextLine();
79       }
80 
81       if (line != wxT("offset"))
82          return false;
83       xmlFile.WriteAttr(wxT("offset"), f->GetNextLine());
84 
85       long envLen;
86 
87       if (f->GetNextLine() != wxT("EnvNumPoints"))
88          return false;
89       line = f->GetNextLine();
90       line.ToLong(&envLen);
91       if (envLen < 0 || envLen > 10000)
92          return false;
93 
94       size_t envStart = f->GetCurrentLine();
95       if (f->GetLineCount() < envStart+(2*envLen)+1)
96          return false;
97 
98       f->GoToLine(envStart+(2*envLen));
99       if (f->GetNextLine() != wxT("EnvEnd"))
100          return false;
101       if (f->GetNextLine() != wxT("numSamples"))
102          return false;
103 
104       wxString numSamples = f->GetNextLine();
105 
106       if (f->GetNextLine() != wxT("rate"))
107          return false;
108 
109       xmlFile.WriteAttr(wxT("rate"), f->GetNextLine());
110 
111       if (envLen > 0) {
112          xmlFile.StartTag(wxT("envelope"));
113          xmlFile.WriteAttr(wxT("numpoints"), envLen);
114 
115          long i;
116          for(i=0; i<envLen; i++) {
117             xmlFile.StartTag(wxT("controlpoint"));
118             xmlFile.WriteAttr(wxT("t"), f->GetLine(envStart + 2*i + 1));
119             xmlFile.WriteAttr(wxT("val"), f->GetLine(envStart + 2*i + 2));
120             xmlFile.EndTag(wxT("controlpoint"));
121          }
122 
123          xmlFile.EndTag(wxT("envelope"));
124       }
125 
126       if (f->GetNextLine() != wxT("numBlocks"))
127          return false;
128       long numBlocks;
129       line = f->GetNextLine();
130       line.ToLong(&numBlocks);
131 
132       if (numBlocks < 0 || numBlocks > 131072)
133          return false;
134 
135       xmlFile.StartTag(wxT("sequence"));
136       xmlFile.WriteAttr(wxT("maxsamples"), 524288);
137       xmlFile.WriteAttr(wxT("sampleformat"), 131073);
138       xmlFile.WriteAttr(wxT("numsamples"), numSamples);
139 
140       long b;
141       for(b=0; b<numBlocks; b++) {
142          wxString start;
143          wxString len;
144          wxString name;
145 
146          if (f->GetNextLine() != wxT("Block start"))
147             return false;
148          start = f->GetNextLine();
149          if (f->GetNextLine() != wxT("Block len"))
150             return false;
151          len = f->GetNextLine();
152          if (f->GetNextLine() != wxT("Block info"))
153             return false;
154          name = f->GetNextLine();
155 
156          xmlFile.StartTag(wxT("waveblock"));
157          xmlFile.WriteAttr(wxT("start"), start);
158 
159          xmlFile.StartTag(wxT("legacyblockfile"));
160          if (name == wxT("Alias")) {
161             wxString aliasPath = f->GetNextLine();
162             wxString localLen = f->GetNextLine();
163             wxString aliasStart = f->GetNextLine();
164             wxString aliasLen = f->GetNextLine();
165             wxString aliasChannel = f->GetNextLine();
166             wxString localName = f->GetNextLine();
167 
168             xmlFile.WriteAttr(wxT("name"), localName);
169             xmlFile.WriteAttr(wxT("alias"), 1);
170             xmlFile.WriteAttr(wxT("aliaspath"), aliasPath);
171 
172             // This was written but not read again?
173             xmlFile.WriteAttr(wxT("aliasstart"), aliasStart);
174 
175             xmlFile.WriteAttr(wxT("aliaslen"), aliasLen);
176             xmlFile.WriteAttr(wxT("aliaschannel"), aliasChannel);
177             xmlFile.WriteAttr(wxT("summarylen"), localLen);
178             xmlFile.WriteAttr(wxT("norms"), 1);
179          }
180          else {
181             xmlFile.WriteAttr(wxT("name"), name);
182             xmlFile.WriteAttr(wxT("len"), len);
183             xmlFile.WriteAttr(wxT("summarylen"), 8244);
184             xmlFile.WriteAttr(wxT("norms"), 1);
185          }
186          xmlFile.EndTag(wxT("legacyblockfile"));
187 
188          xmlFile.EndTag(wxT("waveblock"));
189       }
190 
191       xmlFile.EndTag(wxT("sequence"));
192       xmlFile.EndTag(wxT("wavetrack"));
193 
194       return true;
195    }
196    else if (kind == wxT("LabelTrack")) {
197       line = f->GetNextLine();
198       if (line != wxT("NumMLabels"))
199          return false;
200 
201       long numLabels, l;
202 
203       line = f->GetNextLine();
204       line.ToLong(&numLabels);
205       if (numLabels < 0 || numLabels > 1000000)
206          return false;
207 
208       xmlFile.StartTag(wxT("labeltrack"));
209       xmlFile.WriteAttr(wxT("name"), wxT("Labels"));
210       xmlFile.WriteAttr(wxT("numlabels"), numLabels);
211 
212       for(l=0; l<numLabels; l++) {
213          wxString t, title;
214 
215          t = f->GetNextLine();
216          title = f->GetNextLine();
217 
218          xmlFile.StartTag(wxT("label"));
219          xmlFile.WriteAttr(wxT("t"), t);
220          xmlFile.WriteAttr(wxT("title"), title);
221          xmlFile.EndTag(wxT("label"));
222       }
223 
224       xmlFile.EndTag(wxT("labeltrack"));
225 
226       line = f->GetNextLine();
227       if (line != wxT("MLabelsEnd"))
228          return false;
229 
230       return true;
231    }
232    else if (kind == wxT("NoteTrack")) {
233       // Just skip over it - they didn't even work in version 1.0!
234 
235       do {
236          line = f->GetNextLine();
237          if (line == wxT("WaveTrack") ||
238              line == wxT("NoteTrack") ||
239              line == wxT("LabelTrack") ||
240              line == wxT("EndTracks")) {
241             f->GoToLine(f->GetCurrentLine()-1);
242             return true;
243          }
244       } while (f->GetCurrentLine() < f->GetLineCount());
245 
246       return false;
247    }
248    else
249       return false;
250 }
251 
ConvertLegacyProjectFile(const wxFileName & filename)252 bool ConvertLegacyProjectFile(const wxFileName &filename)
253 {
254    wxTextFile f;
255 
256    const wxString name = filename.GetFullPath();
257    f.Open( name );
258    if (!f.IsOpened())
259       return false;
260 
261    return GuardedCall< bool >( [&] {
262       XMLFileWriter xmlFile{ name, XO("Error Converting Legacy Project File") };
263 
264       xmlFile.Write(wxT("<?xml version=\"1.0\"?>\n"));
265 
266       wxString label;
267       wxString value;
268 
269       if (f.GetFirstLine() != wxT("AudacityProject"))
270          return false;
271       if (f.GetNextLine() != wxT("Version"))
272          return false;
273       if (f.GetNextLine() != wxT("0.95"))
274          return false;
275       if (f.GetNextLine() != wxT("projName"))
276          return false;
277 
278       xmlFile.StartTag(wxT("audacityproject"));
279       xmlFile.WriteAttr(wxT("projname"), f.GetNextLine());
280       xmlFile.WriteAttr(wxT("version"), wxT("1.1.0"));
281       xmlFile.WriteAttr(wxT("audacityversion"),AUDACITY_VERSION_STRING);
282 
283       label = f.GetNextLine();
284       while (label != wxT("BeginTracks")) {
285          xmlFile.WriteAttr(label, f.GetNextLine());
286          label = f.GetNextLine();
287       }
288 
289       label = f.GetNextLine();
290       while (label != wxT("EndTracks")) {
291          bool success = ConvertLegacyTrack(&f, xmlFile);
292          if (!success)
293             return false;
294          label = f.GetNextLine();
295       }
296 
297       // Close original before Commit() tries to overwrite it.
298       f.Close();
299 
300       xmlFile.EndTag(wxT("audacityproject"));
301       xmlFile.Commit();
302 
303       ::AudacityMessageBox(
304          XO(
305 "Converted a 1.0 project file to the new format.\nThe old file has been saved as '%s'")
306             .Format( xmlFile.GetBackupName() ),
307          XO("Opening Audacity Project"));
308 
309       return true;
310    } );
311 }
312