Audacity  2.2.2
FileNames.cpp
Go to the documentation of this file.
1 /**********************************************************************
2 
3  Audacity: A Digital Audio Editor
4 
5  FileNames.cpp
6 
7  James Crook
8 
9 ********************************************************************//********************************************************************/
22 
23 #include "Audacity.h"
24 
25 #include <wx/defs.h>
26 #include <wx/filename.h>
27 #include <wx/intl.h>
28 #include <wx/stdpaths.h>
29 #include "Prefs.h"
30 #include "FileNames.h"
31 #include "Internat.h"
32 #include "PlatformCompatibility.h"
33 #include "wxFileNameWrapper.h"
34 #include "../lib-src/FileDialog/FileDialog.h"
35 
36 #if defined(__WXMAC__) || defined(__WXGTK__)
37 #include <dlfcn.h>
38 #endif
39 
40 #if defined(__WXMSW__)
41 #include <windows.h>
42 #endif
43 
44 static wxString gDataDir;
45 
47  const wxString& file1, const wxString& file2, bool overwrite)
48 {
49 #ifdef __WXMSW__
50 
51  // workaround not needed
52  return wxCopyFile(file1, file2, overwrite);
53 
54 #else
55  // PRL: Compensate for buggy wxCopyFile that returns false success,
56  // which was a cause of case 4 in comment 10 of
57  // http://bugzilla.audacityteam.org/show_bug.cgi?id=1759
58  // Destination file was created, but was empty
59  // Bug was introduced after wxWidgets 2.8.12 at commit
60  // 0597e7f977c87d107e24bf3e95ebfa3d60efc249 of wxWidgets repo
61 
62  bool existed = wxFileExists(file2);
63  bool result = wxCopyFile(file1, file2, overwrite) &&
64  wxFile{ file1 }.Length() == wxFile{ file2 }.Length();
65  if (!result && !existed)
66  wxRemoveFile(file2);
67  return result;
68 
69 #endif
70 }
71 
72 wxString FileNames::MkDir(const wxString &Str)
73 {
74  // Behaviour of wxFileName::DirExists() and wxFileName::MkDir() has
75  // changed between wx2.6 and wx2.8, so we use static functions instead.
76  if (!wxFileName::DirExists(Str))
77  wxFileName::Mkdir(Str, 511, wxPATH_MKDIR_FULL);
78 
79  return Str;
80 }
81 
87 {
88  return FileNames::MkDir(gPrefs->Read(wxT("/Directories/TempDir"), wxT("")));
89 }
90 
91 // originally an ExportMultiple method. Append suffix if newName appears in otherNames.
92 void FileNames::MakeNameUnique(wxArrayString &otherNames, wxFileName &newName)
93 {
94  if (otherNames.Index(newName.GetFullName(), false) >= 0) {
95  int i=2;
96  wxString orig = newName.GetName();
97  do {
98  newName.SetName(wxString::Format(wxT("%s-%d"), orig, i));
99  i++;
100  } while (otherNames.Index(newName.GetFullName(), false) >= 0);
101  }
102  otherNames.Add(newName.GetFullName());
103 }
104 
105 
106 
107 //
108 // Audacity user data directories
110 {
111  wxFileName autoSaveDir(FileNames::DataDir(), wxT("AutoSave"));
112  return FileNames::MkDir(autoSaveDir.GetFullPath());
113 }
114 
115 // The APP name has upercase first letter (so that Quit Audacity is correctly
116 // capitalised on Mac, but we want lower case APP name in paths.
117 // This function does that substitution, IF the last component of
118 // the path is 'Audacity'.
119 wxString FileNames::LowerCaseAppNameInPath( const wxString & dirIn){
120  wxString dir = dirIn;
121  // BUG 1577 Capitalisation of Audacity in path...
122  if( dir.EndsWith( "Audacity" ) )
123  {
124  int nChars = dir.Length() - wxString( "Audacity" ).Length();
125  dir = dir.Left( nChars ) + "audacity";
126  }
127  return dir;
128 }
129 
131 {
132  // LLL: Wouldn't you know that as of WX 2.6.2, there is a conflict
133  // between wxStandardPaths and wxConfig under Linux. The latter
134  // creates a normal file as "$HOME/.audacity", while the former
135  // expects the ".audacity" portion to be a directory.
136  if (gDataDir.IsEmpty())
137  {
138  // If there is a directory "Portable Settings" relative to the
139  // executable's EXE file, the prefs are stored in there, otherwise
140  // the prefs are stored in the user data dir provided by the OS.
141  wxFileName exePath(PlatformCompatibility::GetExecutablePath());
142 #if defined(__WXMAC__)
143  // Path ends for example in "Audacity.app/Contents/MacOSX"
144  //exePath.RemoveLastDir();
145  //exePath.RemoveLastDir();
146  // just remove the MacOSX part.
147  exePath.RemoveLastDir();
148 #endif
149  wxFileName portablePrefsPath(exePath.GetPath(), wxT("Portable Settings"));
150 
151  if (::wxDirExists(portablePrefsPath.GetFullPath()))
152  {
153  // Use "Portable Settings" folder
154  gDataDir = portablePrefsPath.GetFullPath();
155  } else
156  {
157  // Use OS-provided user data dir folder
158  wxString dataDir( LowerCaseAppNameInPath( wxStandardPaths::Get().GetUserDataDir() ));
159 #if defined( __WXGTK__ )
160  dataDir = dataDir + wxT("-data");
161 #endif
162  gDataDir = FileNames::MkDir(dataDir);
163  }
164  }
165  return gDataDir;
166 }
167 
169  wxString resourcesDir( LowerCaseAppNameInPath( wxStandardPaths::Get().GetResourcesDir() ));
170  return resourcesDir;
171 }
172 
174 {
175 #if defined(__WXMAC__)
176  wxFileName exePath(PlatformCompatibility::GetExecutablePath());
177  // Path ends for example in "Audacity.app/Contents/MacOSX"
178  //exePath.RemoveLastDir();
179  //exePath.RemoveLastDir();
180  // just remove the MacOSX part.
181  exePath.RemoveLastDir();
182 
183  //for mac this puts us within the .app: Audacity.app/Contents/SharedSupport/
184  return wxFileName( exePath.GetPath()+wxT("/help/manual"), wxEmptyString ).GetFullPath();
185 #else
186  //linux goes into /*prefix*/share/audacity/
187  //windows (probably) goes into the dir containing the .exe
188  wxString dataDir = FileNames::LowerCaseAppNameInPath( wxStandardPaths::Get().GetDataDir());
189  return wxFileName( dataDir+wxT("/help/manual"), wxEmptyString ).GetFullPath();
190 #endif
191 }
192 
194 {
195  // Don't force creation of it
196  return wxFileName{ DataDir(), wxT("Chains") }.GetFullPath();
197 }
198 
200 {
201  return FileNames::MkDir( wxFileName( DataDir(), wxT("Macros") ).GetFullPath() );
202 }
203 
205 {
206  return FileNames::MkDir( wxFileName( DataDir(), wxT("NRP") ).GetFullPath() );
207 }
208 
210 {
211  return wxFileName( NRPDir(), wxT("noisegate.nrp") ).GetFullPath();
212 }
213 
215 {
216  return FileNames::MkDir( wxFileName( DataDir(), wxT("Plug-Ins") ).GetFullPath() );
217 }
218 
220 {
221  return wxFileName( DataDir(), wxT("pluginregistry.cfg") ).GetFullPath();
222 }
223 
225 {
226  return wxFileName( DataDir(), wxT("pluginsettings.cfg") ).GetFullPath();
227 }
228 
230 {
231  wxFileName baseDir;
232 
233 #if defined(__WXMAC__)
235 
236  // Path ends for example in "Audacity.app/Contents/MacOSX"
237  //baseDir.RemoveLastDir();
238  //baseDir.RemoveLastDir();
239  // just remove the MacOSX part.
240  baseDir.RemoveLastDir();
241 #elif defined(__WXMSW__)
242  // Don't use wxStandardPaths::Get().GetDataDir() since it removes
243  // the "Debug" directory in debug builds.
245 #else
246  // Linux goes into /*prefix*/share/audacity/
247  baseDir = FileNames::LowerCaseAppNameInPath(wxStandardPaths::Get().GetDataDir());
248 #endif
249 
250  return baseDir.GetPath();
251 }
252 
254 {
255  wxFileName modulesDir(BaseDir(), wxEmptyString);
256 
257  modulesDir.AppendDir(wxT("modules"));
258 
259  return modulesDir.GetFullPath();
260 }
261 
263 {
264  return FileNames::MkDir( wxFileName( DataDir(), wxT("Theme") ).GetFullPath() );
265 }
266 
268 {
269  return FileNames::MkDir( wxFileName( ThemeDir(), wxT("Components") ).GetFullPath() );
270 }
271 
273 {
274  return wxFileName( ThemeDir(), wxT("ImageCache.png") ).GetFullPath();
275 }
276 
278 {
279  return wxFileName( ThemeDir(), wxT("ImageCache.htm") ).GetFullPath();
280 }
281 
283 {
284  return wxFileName( ThemeDir(), wxT("ThemeImageDefsAsCee.h") ).GetFullPath();
285 }
286 
288 {
289 // DA: Theme sourcery file name.
290 #ifndef EXPERIMENTAL_DA
291  return wxFileName( ThemeDir(), wxT("ThemeAsCeeCode.h") ).GetFullPath();
292 #else
293  return wxFileName( ThemeDir(), wxT("DarkThemeAsCeeCode.h") ).GetFullPath();
294 #endif
295 }
296 
297 wxString FileNames::ThemeComponent(const wxString &Str)
298 {
299  return wxFileName( ThemeComponentsDir(), Str, wxT("png") ).GetFullPath();
300 }
301 
302 //
303 // Returns the full path of program module (.exe, .dll, .so, .dylib) containing address
304 //
305 wxString FileNames::PathFromAddr(void *addr)
306 {
307  wxFileName name;
308 
309 #if defined(__WXMAC__) || defined(__WXGTK__)
310  Dl_info info;
311  if (dladdr(addr, &info)) {
312  char realname[PLATFORM_MAX_PATH + 1];
313  int len;
314  name = LAT1CTOWX(info.dli_fname);
315  len = readlink(OSINPUT(name.GetFullPath()), realname, PLATFORM_MAX_PATH);
316  if (len > 0) {
317  realname[len] = 0;
318  name.SetFullName(LAT1CTOWX(realname));
319  }
320  }
321 #elif defined(__WXMSW__) && defined(_UNICODE)
322  // The GetModuleHandlEx() function did not appear until Windows XP and
323  // GetModuleFileName() did appear until Windows 2000, so we have to
324  // check for them at runtime.
325  typedef BOOL (WINAPI *getmodulehandleex)(DWORD dwFlags, LPCWSTR lpModuleName, HMODULE* phModule);
326  typedef DWORD (WINAPI *getmodulefilename)(HMODULE hModule, LPWCH lpFilename, DWORD nSize);
327  getmodulehandleex gmhe =
328  (getmodulehandleex) GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")),
329  "GetModuleHandleExW");
330  getmodulefilename gmfn =
331  (getmodulefilename) GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")),
332  "GetModuleFileNameW");
333 
334  if (gmhe != NULL && gmfn != NULL) {
335  HMODULE module;
336  if (gmhe(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
337  (LPTSTR) addr,
338  &module)) {
339  TCHAR path[MAX_PATH];
340  DWORD nSize;
341 
342  nSize = gmfn(module, path, MAX_PATH);
343  if (nSize && nSize < MAX_PATH) {
344  name = LAT1CTOWX(path);
345  }
346  }
347  }
348 #endif
349 
350  return name.GetFullPath();
351 }
352 
354 (const wxString &preference)
355 {
356  wxFileNameWrapper result;
357  result.AssignHomeDir();
358 
359 #ifdef __WIN32__
360  result.SetPath(gPrefs->Read(
361  preference, result.GetPath(wxPATH_GET_VOLUME) + "\\Documents\\Audacity"));
362  // The path might not exist.
363  // There is no error if the path could not be created. That's OK.
364  // The dialog that Audacity offers will allow the user to select a valid directory.
365  result.Mkdir(0755, wxPATH_MKDIR_FULL);
366 #else
367  result.SetPath(gPrefs->Read( preference, result.GetPath() + "/Documents"));
368 #endif
369 
370  return result;
371 }
372 
373 namespace {
374  wxString PreferenceKey(FileNames::Operation op)
375  {
376  wxString key;
377  switch (op) {
379  key = wxT("/DefaultOpenPath"); break;
381  key = wxT("/DefaultExportPath"); break;
383  default:
384  break;
385  }
386  return key;
387  }
388 }
389 
391 {
392  auto key = PreferenceKey(op);
393  if (key.empty())
394  return wxString{};
395  else
396  return DefaultToDocumentsFolder(key).GetPath();
397 }
398 
399 void FileNames::UpdateDefaultPath(Operation op, const wxString &path)
400 {
401  if (path.empty())
402  return;
403  auto key = PreferenceKey(op);
404  if (!key.empty()) {
405  gPrefs->Write(key, ::wxPathOnly(path));
406  gPrefs->Flush();
407  }
408 }
409 
410 wxString
412  const wxString& message,
413  const wxString& default_path,
414  const wxString& default_filename,
415  const wxString& default_extension,
416  const wxString& wildcard,
417  int flags,
418  wxWindow *parent)
419 {
420  return WithDefaultPath(op, default_path, [&](const wxString &path) {
421  return FileSelector(
422  message, path, default_filename, default_extension,
423  wildcard, flags, parent, wxDefaultCoord, wxDefaultCoord);
424  });
425 }
static wxString FindDefaultPath(Operation op)
Definition: FileNames.cpp:390
AudacityPrefs * gPrefs
Definition: Prefs.cpp:73
static wxString ThemeDir()
Definition: FileNames.cpp:262
static const wxString & GetExecutablePath()
static wxFileNameWrapper DefaultToDocumentsFolder(const wxString &preference)
Definition: FileNames.cpp:354
static wxString MacroDir()
Definition: FileNames.cpp:199
static wxString ThemeCacheAsCee()
Definition: FileNames.cpp:287
static wxString PluginSettings()
Definition: FileNames.cpp:224
static void UpdateDefaultPath(Operation op, const wxString &path)
Definition: FileNames.cpp:399
static wxString ThemeCacheHtm()
Definition: FileNames.cpp:277
static wxString ThemeComponent(const wxString &Str)
Definition: FileNames.cpp:297
static wxString PathFromAddr(void *addr)
Definition: FileNames.cpp:305
#define PLATFORM_MAX_PATH
Definition: Audacity.h:118
static wxString BaseDir()
Definition: FileNames.cpp:229
static wxString LowerCaseAppNameInPath(const wxString &dirIn)
Definition: FileNames.cpp:119
static wxString ThemeImageDefsAsCee()
Definition: FileNames.cpp:282
static wxString HtmlHelpDir()
Definition: FileNames.cpp:173
#define OSINPUT(X)
Definition: Internat.h:174
static bool CopyFile(const wxString &file1, const wxString &file2, bool overwrite=true)
Definition: FileNames.cpp:46
wxString FileSelector(const wxString &title, const wxString &defaultDir, const wxString &defaultFileName, const wxString &defaultExtension, const wxString &filter, int flags, wxWindow *parent, int x, int y)
Definition: FileDialog.cpp:61
#define LAT1CTOWX(X)
Definition: Internat.h:180
static wxString gDataDir
Definition: FileNames.cpp:44
static wxString TempDir()
Definition: FileNames.cpp:86
static wxString AutoSaveDir()
Definition: FileNames.cpp:109
static wxString SelectFile(Operation op, const wxString &message, const wxString &default_path, const wxString &default_filename, const wxString &default_extension, const wxString &wildcard, int flags, wxWindow *parent)
Definition: FileNames.cpp:411
static wxString ResourcesDir()
Definition: FileNames.cpp:168
const wxChar * name
Definition: Distortion.cpp:94
static wxString PluginRegistry()
Definition: FileNames.cpp:219
static wxString ThemeCachePng()
Definition: FileNames.cpp:272
static wxString NRPFile()
Definition: FileNames.cpp:209
static wxString ModulesDir()
Definition: FileNames.cpp:253
static wxString DataDir()
Audacity user data directory.
Definition: FileNames.cpp:130
static wxString ThemeComponentsDir()
Definition: FileNames.cpp:267
static wxString MkDir(const wxString &Str)
Definition: FileNames.cpp:72
static wxString WithDefaultPath(Operation op, const wxString &defaultPath, F function)
Definition: FileNames.h:92
static wxString PlugInDir()
The user plug-in directory (not a system one)
Definition: FileNames.cpp:214
static wxString NRPDir()
Definition: FileNames.cpp:204
static wxString LegacyChainDir()
Definition: FileNames.cpp:193
static void MakeNameUnique(wxArrayString &otherNames, wxFileName &newName)
Definition: FileNames.cpp:92