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  return FileNames::MkDir( wxFileName( DataDir(), wxT("Chains") ).GetFullPath() );
196 }
197 
199 {
200  return FileNames::MkDir( wxFileName( DataDir(), wxT("NRP") ).GetFullPath() );
201 }
202 
204 {
205  return wxFileName( NRPDir(), wxT("noisegate.nrp") ).GetFullPath();
206 }
207 
209 {
210  return FileNames::MkDir( wxFileName( DataDir(), wxT("Plug-Ins") ).GetFullPath() );
211 }
212 
214 {
215  return wxFileName( DataDir(), wxT("pluginregistry.cfg") ).GetFullPath();
216 }
217 
219 {
220  return wxFileName( DataDir(), wxT("pluginsettings.cfg") ).GetFullPath();
221 }
222 
224 {
225  wxFileName baseDir;
226 
227 #if defined(__WXMAC__)
229 
230  // Path ends for example in "Audacity.app/Contents/MacOSX"
231  //baseDir.RemoveLastDir();
232  //baseDir.RemoveLastDir();
233  // just remove the MacOSX part.
234  baseDir.RemoveLastDir();
235 #elif defined(__WXMSW__)
236  // Don't use wxStandardPaths::Get().GetDataDir() since it removes
237  // the "Debug" directory in debug builds.
239 #else
240  // Linux goes into /*prefix*/share/audacity/
241  baseDir = FileNames::LowerCaseAppNameInPath(wxStandardPaths::Get().GetDataDir());
242 #endif
243 
244  return baseDir.GetPath();
245 }
246 
248 {
249  wxFileName modulesDir(BaseDir(), wxEmptyString);
250 
251  modulesDir.AppendDir(wxT("modules"));
252 
253  return modulesDir.GetFullPath();
254 }
255 
257 {
258  return FileNames::MkDir( wxFileName( DataDir(), wxT("Theme") ).GetFullPath() );
259 }
260 
262 {
263  return FileNames::MkDir( wxFileName( ThemeDir(), wxT("Components") ).GetFullPath() );
264 }
265 
267 {
268  return wxFileName( ThemeDir(), wxT("ImageCache.png") ).GetFullPath();
269 }
270 
272 {
273  return wxFileName( ThemeDir(), wxT("ImageCache.htm") ).GetFullPath();
274 }
275 
277 {
278  return wxFileName( ThemeDir(), wxT("ThemeImageDefsAsCee.h") ).GetFullPath();
279 }
280 
282 {
283 // DA: Theme sourcery file name.
284 #ifndef EXPERIMENTAL_DA
285  return wxFileName( ThemeDir(), wxT("ThemeAsCeeCode.h") ).GetFullPath();
286 #else
287  return wxFileName( ThemeDir(), wxT("DarkThemeAsCeeCode.h") ).GetFullPath();
288 #endif
289 }
290 
291 wxString FileNames::ThemeComponent(const wxString &Str)
292 {
293  return wxFileName( ThemeComponentsDir(), Str, wxT("png") ).GetFullPath();
294 }
295 
296 //
297 // Returns the full path of program module (.exe, .dll, .so, .dylib) containing address
298 //
299 wxString FileNames::PathFromAddr(void *addr)
300 {
301  wxFileName name;
302 
303 #if defined(__WXMAC__) || defined(__WXGTK__)
304  Dl_info info;
305  if (dladdr(addr, &info)) {
306  char realname[PLATFORM_MAX_PATH + 1];
307  int len;
308  name = LAT1CTOWX(info.dli_fname);
309  len = readlink(OSINPUT(name.GetFullPath()), realname, PLATFORM_MAX_PATH);
310  if (len > 0) {
311  realname[len] = 0;
312  name.SetFullName(LAT1CTOWX(realname));
313  }
314  }
315 #elif defined(__WXMSW__) && defined(_UNICODE)
316  // The GetModuleHandlEx() function did not appear until Windows XP and
317  // GetModuleFileName() did appear until Windows 2000, so we have to
318  // check for them at runtime.
319  typedef BOOL (WINAPI *getmodulehandleex)(DWORD dwFlags, LPCWSTR lpModuleName, HMODULE* phModule);
320  typedef DWORD (WINAPI *getmodulefilename)(HMODULE hModule, LPWCH lpFilename, DWORD nSize);
321  getmodulehandleex gmhe =
322  (getmodulehandleex) GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")),
323  "GetModuleHandleExW");
324  getmodulefilename gmfn =
325  (getmodulefilename) GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")),
326  "GetModuleFileNameW");
327 
328  if (gmhe != NULL && gmfn != NULL) {
329  HMODULE module;
330  if (gmhe(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
331  (LPTSTR) addr,
332  &module)) {
333  TCHAR path[MAX_PATH];
334  DWORD nSize;
335 
336  nSize = gmfn(module, path, MAX_PATH);
337  if (nSize && nSize < MAX_PATH) {
338  name = LAT1CTOWX(path);
339  }
340  }
341  }
342 #endif
343 
344  return name.GetFullPath();
345 }
346 
348 (const wxString &preference)
349 {
350  wxFileNameWrapper result;
351  result.AssignHomeDir();
352 
353 #ifdef __WIN32__
354  result.SetPath(gPrefs->Read(
355  preference, result.GetPath(wxPATH_GET_VOLUME) + "\\Documents\\Audacity"));
356  // The path might not exist.
357  // There is no error if the path could not be created. That's OK.
358  // The dialog that Audacity offers will allow the user to select a valid directory.
359  result.Mkdir(0755, wxPATH_MKDIR_FULL);
360 #else
361  result.SetPath(gPrefs->Read( preference, result.GetPath() + "/Documents"));
362 #endif
363 
364  return result;
365 }
366 
367 namespace {
368  wxString PreferenceKey(FileNames::Operation op)
369  {
370  wxString key;
371  switch (op) {
373  key = wxT("/DefaultOpenPath"); break;
375  key = wxT("/DefaultExportPath"); break;
377  default:
378  break;
379  }
380  return key;
381  }
382 }
383 
385 {
386  auto key = PreferenceKey(op);
387  if (key.empty())
388  return wxString{};
389  else
390  return DefaultToDocumentsFolder(key).GetPath();
391 }
392 
393 void FileNames::UpdateDefaultPath(Operation op, const wxString &path)
394 {
395  if (path.empty())
396  return;
397  auto key = PreferenceKey(op);
398  if (!key.empty()) {
399  gPrefs->Write(key, ::wxPathOnly(path));
400  gPrefs->Flush();
401  }
402 }
403 
404 wxString
406  const wxString& message,
407  const wxString& default_path,
408  const wxString& default_filename,
409  const wxString& default_extension,
410  const wxString& wildcard,
411  int flags,
412  wxWindow *parent)
413 {
414  return WithDefaultPath(op, default_path, [&](const wxString &path) {
415  return FileSelector(
416  message, path, default_filename, default_extension,
417  wildcard, flags, parent, wxDefaultCoord, wxDefaultCoord);
418  });
419 }
static wxString FindDefaultPath(Operation op)
Definition: FileNames.cpp:384
static wxString ThemeDir()
Definition: FileNames.cpp:256
static const wxString & GetExecutablePath()
static wxFileNameWrapper DefaultToDocumentsFolder(const wxString &preference)
Definition: FileNames.cpp:348
static wxString ThemeCacheAsCee()
Definition: FileNames.cpp:281
static wxString PluginSettings()
Definition: FileNames.cpp:218
static void UpdateDefaultPath(Operation op, const wxString &path)
Definition: FileNames.cpp:393
static wxString ThemeCacheHtm()
Definition: FileNames.cpp:271
static wxString ThemeComponent(const wxString &Str)
Definition: FileNames.cpp:291
static wxString PathFromAddr(void *addr)
Definition: FileNames.cpp:299
#define PLATFORM_MAX_PATH
Definition: Audacity.h:118
static wxString BaseDir()
Definition: FileNames.cpp:223
static wxString LowerCaseAppNameInPath(const wxString &dirIn)
Definition: FileNames.cpp:119
static wxString ThemeImageDefsAsCee()
Definition: FileNames.cpp:276
static wxString HtmlHelpDir()
Definition: FileNames.cpp:173
wxFileConfig * gPrefs
Definition: Prefs.cpp:72
static wxString ChainDir()
Definition: FileNames.cpp:193
#define OSINPUT(X)
Definition: Internat.h:162
static bool CopyFile(const wxString &file1, const wxString &file2, bool overwrite=true)
Definition: FileNames.cpp:46
#define LAT1CTOWX(X)
Definition: Internat.h:168
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:405
static wxString ResourcesDir()
Definition: FileNames.cpp:168
const wxChar * name
Definition: Distortion.cpp:94
static wxString PluginRegistry()
Definition: FileNames.cpp:213
static wxString ThemeCachePng()
Definition: FileNames.cpp:266
static wxString NRPFile()
Definition: FileNames.cpp:203
static wxString ModulesDir()
Definition: FileNames.cpp:247
static wxString DataDir()
Audacity user data directory.
Definition: FileNames.cpp:130
static wxString ThemeComponentsDir()
Definition: FileNames.cpp:261
static wxString MkDir(const wxString &Str)
Definition: FileNames.cpp:72
static wxString WithDefaultPath(Operation op, const wxString &defaultPath, F function)
Definition: FileNames.h:91
static wxString PlugInDir()
The user plug-in directory (not a system one)
Definition: FileNames.cpp:208
static wxString NRPDir()
Definition: FileNames.cpp:198
static void MakeNameUnique(wxArrayString &otherNames, wxFileName &newName)
Definition: FileNames.cpp:92