File Property Dialog Rewrite (phase 1)
This commit is contained in:
@@ -131,6 +131,8 @@ else()
|
||||
endif()
|
||||
|
||||
set (PIPEDAL_SOURCES
|
||||
FilePropertyDirectoryTree.cpp FilePropertyDirectoryTree.hpp
|
||||
FileEntry.cpp FileEntry.hpp
|
||||
atom_object.hpp atom_object.cpp
|
||||
FileBrowserFiles.h
|
||||
FileBrowserFilesFeature.hpp FileBrowserFilesFeature.cpp
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
// Copyright (c) 2024 Robin Davies
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
// this software and associated documentation files (the "Software"), to deal in
|
||||
// the Software without restriction, including without limitation the rights to
|
||||
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
// the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
// subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#include "FileEntry.hpp"
|
||||
|
||||
using namespace pipedal;
|
||||
|
||||
JSON_MAP_BEGIN(FileEntry)
|
||||
JSON_MAP_REFERENCE(FileEntry,filename)
|
||||
JSON_MAP_REFERENCE(FileEntry,isDirectory)
|
||||
|
||||
JSON_MAP_END()
|
||||
@@ -0,0 +1,40 @@
|
||||
// Copyright (c) 2024 Robin Davies
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
// this software and associated documentation files (the "Software"), to deal in
|
||||
// the Software without restriction, including without limitation the rights to
|
||||
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
// the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
// subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "json.hpp"
|
||||
|
||||
namespace pipedal {
|
||||
|
||||
class FileEntry {
|
||||
public:
|
||||
FileEntry() { }
|
||||
FileEntry(std::string filename,bool isDirectory)
|
||||
:filename_(filename), isDirectory_(isDirectory)
|
||||
{
|
||||
|
||||
}
|
||||
std::string filename_;
|
||||
bool isDirectory_ = false;
|
||||
|
||||
DECLARE_JSON_MAP(FileEntry);
|
||||
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
// Copyright (c) 2024 Robin Davies
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
// this software and associated documentation files (the "Software"), to deal in
|
||||
// the Software without restriction, including without limitation the rights to
|
||||
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
// the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
// subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#include "FilePropertyDirectoryTree.hpp"
|
||||
|
||||
using namespace pipedal;
|
||||
|
||||
FilePropertyDirectoryTree::FilePropertyDirectoryTree()
|
||||
{
|
||||
}
|
||||
FilePropertyDirectoryTree::FilePropertyDirectoryTree(const std::string &directoryName)
|
||||
: directoryName_(directoryName)
|
||||
{
|
||||
}
|
||||
|
||||
JSON_MAP_BEGIN(FilePropertyDirectoryTree)
|
||||
JSON_MAP_REFERENCE(FilePropertyDirectoryTree, directoryName)
|
||||
JSON_MAP_REFERENCE(FilePropertyDirectoryTree, children)
|
||||
JSON_MAP_END()
|
||||
@@ -0,0 +1,37 @@
|
||||
// Copyright (c) 2024 Robin Davies
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
// this software and associated documentation files (the "Software"), to deal in
|
||||
// the Software without restriction, including without limitation the rights to
|
||||
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
// the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
// subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#pragma once
|
||||
#include "json.hpp"
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
namespace pipedal {
|
||||
class FilePropertyDirectoryTree {
|
||||
public:
|
||||
using ptr = std::unique_ptr<FilePropertyDirectoryTree>;
|
||||
|
||||
FilePropertyDirectoryTree();
|
||||
FilePropertyDirectoryTree(const std::string&directoryName);
|
||||
std::string directoryName_;
|
||||
std::vector<std::unique_ptr<FilePropertyDirectoryTree>> children_;
|
||||
|
||||
DECLARE_JSON_MAP(FilePropertyDirectoryTree);
|
||||
};
|
||||
}
|
||||
@@ -2039,6 +2039,27 @@ std::vector<std::string> PiPedalModel::GetFileList(const UiFileProperty &filePro
|
||||
return std::vector<std::string>(); // don't disclose to users what the problem is.
|
||||
}
|
||||
}
|
||||
std::vector<FileEntry> PiPedalModel::GetFileList2(const std::string &relativePath,const UiFileProperty &fileProperty)
|
||||
{
|
||||
try
|
||||
{
|
||||
return this->storage.GetFileList2(relativePath,fileProperty);
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
Lv2Log::warning("GetFileList() failed: (%s)", e.what());
|
||||
return std::vector<FileEntry>(); // don't disclose to users what the problem is.
|
||||
}
|
||||
}
|
||||
|
||||
std::string PiPedalModel::RenameSampleFile(
|
||||
const std::string&oldRelativePath,
|
||||
const std::string&newRelativePath,
|
||||
const UiFileProperty&uiFileProperty)
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock(mutex);
|
||||
return storage.RenameSampleFile(oldRelativePath,newRelativePath,uiFileProperty);
|
||||
}
|
||||
|
||||
void PiPedalModel::DeleteSampleFile(const std::filesystem::path &fileName)
|
||||
{
|
||||
@@ -2046,6 +2067,20 @@ void PiPedalModel::DeleteSampleFile(const std::filesystem::path &fileName)
|
||||
storage.DeleteSampleFile(fileName);
|
||||
}
|
||||
|
||||
std::string PiPedalModel::CreateNewSampleDirectory(const std::string&relativePath, const UiFileProperty&uiFileProperty)
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock(mutex);
|
||||
return storage.CreateNewSampleDirectory(relativePath, uiFileProperty);
|
||||
|
||||
}
|
||||
FilePropertyDirectoryTree::ptr PiPedalModel::GetSampleDirectoryTree(const UiFileProperty&uiFileProperty)
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock(mutex);
|
||||
return storage.GetSampleDirectoryTree(uiFileProperty);
|
||||
|
||||
}
|
||||
|
||||
|
||||
std::string PiPedalModel::UploadUserFile(const std::string &directory, const std::string &patchProperty, const std::string &filename, const std::string &fileBody)
|
||||
{
|
||||
return storage.UploadUserFile(directory, patchProperty, filename, fileBody);
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
#include <thread>
|
||||
#include "Promise.hpp"
|
||||
#include "AtomConverter.hpp"
|
||||
#include "FileEntry.hpp"
|
||||
|
||||
namespace pipedal
|
||||
{
|
||||
@@ -328,8 +329,13 @@ namespace pipedal
|
||||
void SetFavorites(const std::map<std::string, bool> &favorites);
|
||||
|
||||
std::vector<std::string> GetFileList(const UiFileProperty&fileProperty);
|
||||
std::vector<FileEntry> GetFileList2(const std::string &relativePath,const UiFileProperty&fileProperty);
|
||||
|
||||
void DeleteSampleFile(const std::filesystem::path &fileName);
|
||||
std::string CreateNewSampleDirectory(const std::string&relativePath, const UiFileProperty&uiFileProperty);
|
||||
std::string RenameSampleFile(const std::string&oldRelativePath,const std::string&newRelativePath,const UiFileProperty&uiFileProperty);
|
||||
FilePropertyDirectoryTree::ptr GetSampleDirectoryTree(const UiFileProperty&uiFileProperty);
|
||||
|
||||
std::string UploadUserFile(const std::string &directory, const std::string &patchProperty,const std::string&filename,const std::string&fileBody);
|
||||
uint64_t CreateNewPreset();
|
||||
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
#include "SysExec.hpp"
|
||||
#include "PiPedalAlsa.hpp"
|
||||
#include <filesystem>
|
||||
#include "FileEntry.hpp"
|
||||
|
||||
using namespace std;
|
||||
using namespace pipedal;
|
||||
@@ -58,6 +59,33 @@ JSON_MAP_REFERENCE(GetPatchPropertyBody, propertyUri)
|
||||
JSON_MAP_END()
|
||||
|
||||
|
||||
class CreateNewSampleDirectoryArgs {
|
||||
public:
|
||||
std::string relativePath_;
|
||||
UiFileProperty uiFileProperty_;
|
||||
DECLARE_JSON_MAP(CreateNewSampleDirectoryArgs);
|
||||
};
|
||||
|
||||
JSON_MAP_BEGIN(CreateNewSampleDirectoryArgs)
|
||||
JSON_MAP_REFERENCE(CreateNewSampleDirectoryArgs, relativePath)
|
||||
JSON_MAP_REFERENCE(CreateNewSampleDirectoryArgs, uiFileProperty)
|
||||
JSON_MAP_END()
|
||||
|
||||
class RenameSampleFileArgs {
|
||||
public:
|
||||
std::string oldRelativePath_;
|
||||
std::string newRelativePath_;
|
||||
UiFileProperty uiFileProperty_;
|
||||
DECLARE_JSON_MAP(RenameSampleFileArgs);
|
||||
};
|
||||
|
||||
JSON_MAP_BEGIN(RenameSampleFileArgs)
|
||||
JSON_MAP_REFERENCE(RenameSampleFileArgs, oldRelativePath)
|
||||
JSON_MAP_REFERENCE(RenameSampleFileArgs, newRelativePath)
|
||||
JSON_MAP_REFERENCE(RenameSampleFileArgs, uiFileProperty)
|
||||
JSON_MAP_END()
|
||||
|
||||
|
||||
class Lv2StateChangedBody {
|
||||
public:
|
||||
uint64_t instanceId_;
|
||||
@@ -198,6 +226,21 @@ JSON_MAP_REFERENCE(MonitorResultBody, subscriptionHandle)
|
||||
JSON_MAP_REFERENCE(MonitorResultBody, value)
|
||||
JSON_MAP_END()
|
||||
|
||||
class FileRequestArgs
|
||||
{
|
||||
public:
|
||||
std::string relativePath_;
|
||||
UiFileProperty fileProperty_;
|
||||
|
||||
DECLARE_JSON_MAP(FileRequestArgs);
|
||||
};
|
||||
JSON_MAP_BEGIN(FileRequestArgs)
|
||||
JSON_MAP_REFERENCE(FileRequestArgs, relativePath)
|
||||
JSON_MAP_REFERENCE(FileRequestArgs, fileProperty)
|
||||
JSON_MAP_END()
|
||||
|
||||
|
||||
|
||||
|
||||
class MonitorPortBody
|
||||
{
|
||||
@@ -1417,6 +1460,13 @@ public:
|
||||
std::vector<std::string> list = this->model.GetFileList(fileProperty);
|
||||
this->Reply(replyTo,"requestFileList",list);
|
||||
}
|
||||
else if (message == "requestFileList2")
|
||||
{
|
||||
FileRequestArgs requestArgs;
|
||||
pReader->read(&requestArgs);
|
||||
std::vector<FileEntry> list = this->model.GetFileList2(requestArgs.relativePath_, requestArgs.fileProperty_);
|
||||
this->Reply(replyTo,"requestFileList2",list);
|
||||
}
|
||||
else if (message == "newPreset")
|
||||
{
|
||||
int64_t presetId = this->model.CreateNewPreset();
|
||||
@@ -1430,6 +1480,29 @@ public:
|
||||
this->model.DeleteSampleFile(fileName);
|
||||
this->Reply(replyTo,"deleteUserFile",true);
|
||||
}
|
||||
else if (message == "createNewSampleDirectory")
|
||||
{
|
||||
CreateNewSampleDirectoryArgs args;
|
||||
pReader->read(&args);
|
||||
|
||||
std::string newFileName = this->model.CreateNewSampleDirectory(args.relativePath_,args.uiFileProperty_);
|
||||
this->Reply(replyTo,"createNewSampleDirectory",newFileName);
|
||||
}
|
||||
else if (message == "renameSampleFile")
|
||||
{
|
||||
RenameSampleFileArgs args;
|
||||
pReader->read(&args);
|
||||
|
||||
std::string newFileName = this->model.RenameSampleFile(args.oldRelativePath_,args.newRelativePath_,args.uiFileProperty_);
|
||||
this->Reply(replyTo,"renameSampleFile",newFileName);
|
||||
} else if (message == "GetSampleDirectoryTree"){
|
||||
UiFileProperty uiFileProperty;
|
||||
pReader->read(&uiFileProperty);
|
||||
FilePropertyDirectoryTree::ptr result = model.GetSampleDirectoryTree(uiFileProperty);
|
||||
this->Reply(replyTo,"GetSampleDirectoryTree",result);
|
||||
|
||||
}
|
||||
|
||||
else if (message == "setOnboarding")
|
||||
{
|
||||
bool value;
|
||||
|
||||
+202
-22
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2022-2023 Robin Davies
|
||||
// Copyright (c) 2022-2024 Robin Davies
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
// this software and associated documentation files (the "Software"), to deal in
|
||||
@@ -40,6 +40,7 @@ const char *BANKS_FILENAME = "index.banks";
|
||||
#define USER_SETTINGS_FILENAME "userSettings.json";
|
||||
|
||||
Storage::Storage()
|
||||
: locale("en_US.UTF-8")
|
||||
{
|
||||
SetConfigRoot("~/var/Config");
|
||||
SetDataRoot("~/var/PiPedal");
|
||||
@@ -1467,11 +1468,6 @@ std::vector<MidiBinding> Storage::GetSystemMidiBindings()
|
||||
return result;
|
||||
}
|
||||
|
||||
static bool containsDotDot(const std::string &value)
|
||||
{
|
||||
std::size_t offset = value.find("..");
|
||||
return offset != std::string::npos;
|
||||
}
|
||||
static bool containsDirectorySeparator(const std::string &value)
|
||||
{
|
||||
if (value.find("/") != std::string::npos)
|
||||
@@ -1483,19 +1479,12 @@ static bool containsDirectorySeparator(const std::string &value)
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
static void ThrowPermissionDeniedError()
|
||||
{
|
||||
throw std::logic_error("Permission denied.");
|
||||
}
|
||||
|
||||
class LexicographicCompare
|
||||
{
|
||||
public:
|
||||
bool operator()(const std::string &left, const std::string &right)
|
||||
{
|
||||
return std::lexicographical_compare(left.begin(), left.end(), right.begin(), right.end());
|
||||
}
|
||||
} lexicographicCompare;
|
||||
|
||||
std::vector<std::string> Storage::GetFileList(const UiFileProperty &fileProperty)
|
||||
{
|
||||
@@ -1537,16 +1526,109 @@ std::vector<std::string> Storage::GetFileList(const UiFileProperty &fileProperty
|
||||
|
||||
// sort lexicographically
|
||||
|
||||
std::sort(result.begin(), result.end(), lexicographicCompare);
|
||||
std::sort(result.begin(), result.end(), [this](const std::string&left,const std::string&right) {
|
||||
return this->locale(left,right) < 0;
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
bool Storage::IsValidSampleFile(const std::filesystem::path &fileName)
|
||||
static bool ensureNoDotDot(const std::filesystem::path&path)
|
||||
{
|
||||
for (auto segment_: path)
|
||||
{
|
||||
std::string segment = segment_.string();
|
||||
if (segment.starts_with("."))
|
||||
{
|
||||
// the linux rule: any path that consists of all '.'s.
|
||||
bool valid = false;
|
||||
for (auto c: segment)
|
||||
{
|
||||
if (c != '.')
|
||||
{
|
||||
valid = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!valid)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
std::vector<FileEntry> Storage::GetFileList2(const std::string &relativePath,const UiFileProperty &fileProperty)
|
||||
{
|
||||
if (!ensureNoDotDot(relativePath))
|
||||
{
|
||||
ThrowPermissionDeniedError();
|
||||
}
|
||||
if (!UiFileProperty::IsDirectoryNameValid(fileProperty.directory()))
|
||||
{
|
||||
ThrowPermissionDeniedError();
|
||||
}
|
||||
|
||||
std::vector<FileEntry> result;
|
||||
|
||||
// if fileProperty has a user-accessible directory, push the entire file path.
|
||||
if (fileProperty.directory().size() != 0)
|
||||
{
|
||||
std::filesystem::path audioFileDirectory = this->GetPluginAudioFileDirectory() / fileProperty.directory() / relativePath;
|
||||
try
|
||||
{
|
||||
for (auto const &dir_entry : std::filesystem::directory_iterator(audioFileDirectory))
|
||||
{
|
||||
if (dir_entry.is_regular_file())
|
||||
{
|
||||
auto &path = dir_entry.path();
|
||||
auto name = path.filename().string();
|
||||
if (name.length() > 0 && name[0] != '.') // don't show hidden files.
|
||||
{
|
||||
if (fileProperty.IsValidExtension(path.extension().string()))
|
||||
{
|
||||
// a relative path!
|
||||
result.push_back(FileEntry(path,false));
|
||||
}
|
||||
}
|
||||
} else if (dir_entry.is_directory()) {
|
||||
result.push_back(FileEntry(dir_entry.path(),true));
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (const std::exception &error)
|
||||
{
|
||||
throw std::logic_error("GetFileList failed. Directory not found: " + audioFileDirectory.string());
|
||||
}
|
||||
}
|
||||
|
||||
// sort lexicographically
|
||||
|
||||
std::sort(result.begin(), result.end(),[this](const FileEntry&l, const FileEntry&r) {
|
||||
if (l.isDirectory_ != r.isDirectory_)
|
||||
{
|
||||
return l.isDirectory_ > r.isDirectory_;
|
||||
}
|
||||
return this->locale(l.filename_,r.filename_);
|
||||
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
bool Storage::IsValidSampleFileName(const std::filesystem::path &fileName)
|
||||
{
|
||||
if (!fileName.is_absolute())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (!ensureNoDotDot(fileName))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
std::filesystem::path audioFilePath = this->GetPluginAudioFileDirectory();
|
||||
|
||||
std::filesystem::path parentDirectory = fileName.parent_path();
|
||||
@@ -1557,9 +1639,6 @@ bool Storage::IsValidSampleFile(const std::filesystem::path &fileName)
|
||||
return false;
|
||||
}
|
||||
std::string name = parentDirectory.filename().string();
|
||||
if (name == ".." || name == ".")
|
||||
return false;
|
||||
|
||||
if (parentDirectory == audioFilePath)
|
||||
return true;
|
||||
parentDirectory = parentDirectory.parent_path();
|
||||
@@ -1571,7 +1650,7 @@ bool Storage::IsValidSampleFile(const std::filesystem::path &fileName)
|
||||
}
|
||||
void Storage::DeleteSampleFile(const std::filesystem::path &fileName)
|
||||
{
|
||||
if (!IsValidSampleFile(fileName))
|
||||
if (!IsValidSampleFileName(fileName))
|
||||
{
|
||||
throw std::logic_error("Permission denied.");
|
||||
}
|
||||
@@ -1581,7 +1660,16 @@ void Storage::DeleteSampleFile(const std::filesystem::path &fileName)
|
||||
}
|
||||
try
|
||||
{
|
||||
std::filesystem::remove(fileName);
|
||||
if (std::filesystem::is_directory(fileName))
|
||||
{
|
||||
if (fileName.string().length() > 1) // guard against rm -rf / (bitter experience)
|
||||
{
|
||||
std::filesystem::remove_all(fileName);
|
||||
}
|
||||
}
|
||||
else {
|
||||
std::filesystem::remove(fileName);
|
||||
}
|
||||
}
|
||||
catch (const std::exception &)
|
||||
{
|
||||
@@ -1601,7 +1689,7 @@ std::filesystem::path Storage::MakeUserFilePath(const std::string &directory, co
|
||||
throw std::logic_error("Permission denied.");
|
||||
}
|
||||
std::filesystem::path result = this->GetPluginAudioFileDirectory() / directory / filename;
|
||||
if (!this->IsValidSampleFile(result))
|
||||
if (!this->IsValidSampleFileName(result))
|
||||
{
|
||||
throw std::logic_error("Permission denied.");
|
||||
}
|
||||
@@ -1641,6 +1729,98 @@ std::string Storage::UploadUserFile(const std::string &directory, const std::str
|
||||
return path.string();
|
||||
}
|
||||
|
||||
std::string Storage::CreateNewSampleDirectory(const std::string&relativePath, const UiFileProperty&uiFileProperty)
|
||||
{
|
||||
if (uiFileProperty.directory().empty())
|
||||
{
|
||||
throw std::runtime_error("Invalid UI File Property.");
|
||||
}
|
||||
std::filesystem::path path = this->GetPluginAudioFileDirectory() / uiFileProperty.directory() / relativePath;
|
||||
if (!this->IsValidSampleFileName(path))
|
||||
{
|
||||
throw std::runtime_error("Invalid file name.");
|
||||
}
|
||||
if (std::filesystem::exists(path))
|
||||
{
|
||||
throw std::runtime_error("A directory with that name already exists.");
|
||||
}
|
||||
std::filesystem::create_directories(path);
|
||||
return path;
|
||||
|
||||
}
|
||||
std::string Storage::RenameSampleFile(
|
||||
const std::string&oldRelativePath,
|
||||
const std::string&newRelativePath,
|
||||
const UiFileProperty&uiFileProperty)
|
||||
{
|
||||
if (uiFileProperty.directory().empty())
|
||||
{
|
||||
throw std::runtime_error("Invalid UI File Property.");
|
||||
}
|
||||
std::filesystem::path oldPath = this->GetPluginAudioFileDirectory() / uiFileProperty.directory() / oldRelativePath;
|
||||
if (!this->IsValidSampleFileName(oldPath))
|
||||
{
|
||||
throw std::runtime_error("Invalid file name.");
|
||||
}
|
||||
if (!std::filesystem::exists(oldPath))
|
||||
{
|
||||
throw std::runtime_error("Original path does not exist.");
|
||||
}
|
||||
|
||||
std::filesystem::path newPath = this->GetPluginAudioFileDirectory() / uiFileProperty.directory() / newRelativePath;
|
||||
if (!this->IsValidSampleFileName(newPath))
|
||||
{
|
||||
throw std::runtime_error("Invalid file name.");
|
||||
}
|
||||
if (std::filesystem::exists(newPath))
|
||||
{
|
||||
if (std::filesystem::is_directory(newPath))
|
||||
{
|
||||
throw std::runtime_error("A directory with that name already exists.");
|
||||
} else {
|
||||
throw std::runtime_error("A file with that name already exists.");
|
||||
}
|
||||
}
|
||||
|
||||
std::filesystem::rename(oldPath,newPath);
|
||||
return newPath;
|
||||
|
||||
}
|
||||
|
||||
void Storage::FillSampleDirectoryTree(FilePropertyDirectoryTree*node, const std::filesystem::path&directory) const
|
||||
{
|
||||
for (auto child: std::filesystem::recursive_directory_iterator(directory))
|
||||
{
|
||||
const auto& childPath = child.path();
|
||||
FilePropertyDirectoryTree::ptr childTree = std::make_unique<FilePropertyDirectoryTree>(childPath.filename());
|
||||
FillSampleDirectoryTree(childTree.get(),childPath);
|
||||
node->children_.push_back(std::move(childTree));
|
||||
}
|
||||
std::sort(node->children_.begin(),node->children_.end(),
|
||||
[this](const FilePropertyDirectoryTree::ptr&left,const FilePropertyDirectoryTree::ptr&right)
|
||||
{
|
||||
return this->locale(left->directoryName_,right->directoryName_);
|
||||
});
|
||||
}
|
||||
FilePropertyDirectoryTree::ptr Storage::GetSampleDirectoryTree(const UiFileProperty&uiFileProperty) const
|
||||
{
|
||||
FilePropertyDirectoryTree::ptr result = std::make_unique<FilePropertyDirectoryTree>("");
|
||||
if (uiFileProperty.directory().empty())
|
||||
{
|
||||
throw std::runtime_error("Invalid uiFileProperty");
|
||||
}
|
||||
if (!ensureNoDotDot(uiFileProperty.directory()))
|
||||
{
|
||||
throw std::runtime_error("Invalid uiFileProperty");
|
||||
}
|
||||
std::filesystem::path rootDirectory = this->GetPluginAudioFileDirectory() / uiFileProperty.directory();
|
||||
|
||||
FillSampleDirectoryTree(result.get(),rootDirectory);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
const PluginPresetIndex &Storage::GetPluginPresetIndex()
|
||||
{
|
||||
return pluginPresetIndex;
|
||||
|
||||
+14
-1
@@ -28,7 +28,10 @@
|
||||
#include "JackServerSettings.hpp"
|
||||
#include "WifiConfigSettings.hpp"
|
||||
#include "WifiDirectConfigSettings.hpp"
|
||||
#include "FileEntry.hpp"
|
||||
#include <map>
|
||||
#include <locale>
|
||||
#include "FilePropertyDirectoryTree.hpp"
|
||||
|
||||
|
||||
namespace pipedal {
|
||||
@@ -64,6 +67,7 @@ struct PluginPresetValues {
|
||||
|
||||
class Storage {
|
||||
private:
|
||||
std::locale locale;
|
||||
std::filesystem::path dataRoot;
|
||||
std::filesystem::path configRoot;
|
||||
BankIndex bankIndex;
|
||||
@@ -71,6 +75,7 @@ private:
|
||||
PluginPresetIndex pluginPresetIndex;
|
||||
|
||||
private:
|
||||
void FillSampleDirectoryTree(FilePropertyDirectoryTree*node, const std::filesystem::path&directory) const;
|
||||
|
||||
void MaybeCopyDefaultPresets();
|
||||
static std::string SafeEncodeName(const std::string& name);
|
||||
@@ -149,6 +154,7 @@ public:
|
||||
int64_t DeleteBank(int64_t bankId);
|
||||
|
||||
std::vector<std::string> GetFileList(const UiFileProperty&fileProperty);
|
||||
std::vector<FileEntry> GetFileList2(const std::string&relativePath,const UiFileProperty&fileProperty);
|
||||
|
||||
|
||||
void SetJackChannelSelection(const JackChannelSelection&channelSelection);
|
||||
@@ -176,7 +182,7 @@ private:
|
||||
void SavePluginPresetIndex();
|
||||
|
||||
std::filesystem::path GetPluginPresetPath(const std::string &pluginUri) const;
|
||||
bool IsValidSampleFile(const std::filesystem::path&fileName);
|
||||
bool IsValidSampleFileName(const std::filesystem::path&fileName);
|
||||
std::filesystem::path MakeUserFilePath(const std::string &directory, const std::string&filename);
|
||||
|
||||
public:
|
||||
@@ -213,6 +219,13 @@ public:
|
||||
std::vector<MidiBinding> GetSystemMidiBindings();
|
||||
void DeleteSampleFile(const std::filesystem::path &fileName);
|
||||
std::string UploadUserFile(const std::string &directory, const std::string &patchProperty,const std::string&filename,const std::string&fileBody);
|
||||
std::string CreateNewSampleDirectory(const std::string&relativePath, const UiFileProperty&uiFileProperty);
|
||||
std::string RenameSampleFile(
|
||||
const std::string&oldRelativePath,
|
||||
const std::string&newRelativePath,
|
||||
const UiFileProperty&uiFileProperty);
|
||||
FilePropertyDirectoryTree::ptr GetSampleDirectoryTree(const UiFileProperty&uiFileProperty) const;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user