From ab4361a76b40b56348ec46311121a0552f0c9d6b Mon Sep 17 00:00:00 2001 From: Alexander Tkachev Date: Wed, 6 Jul 2016 18:03:56 +0600 Subject: CLOUD: Make "/create" work One can now create directories through browser. --- backends/networking/sdl_net/client.cpp | 5 +- .../sdl_net/handlers/filespagehandler.cpp | 73 +++++++++++++++++++++ .../networking/sdl_net/handlers/filespagehandler.h | 11 ++++ backends/networking/sdl_net/localwebserver.cpp | 29 ++++++++ backends/networking/sdl_net/localwebserver.h | 1 + backends/networking/wwwroot.zip | Bin 230886 -> 231000 bytes backends/networking/wwwroot/.files.html | 2 + 7 files changed, 119 insertions(+), 2 deletions(-) diff --git a/backends/networking/sdl_net/client.cpp b/backends/networking/sdl_net/client.cpp index 67b45b6cbe..f567891dd8 100644 --- a/backends/networking/sdl_net/client.cpp +++ b/backends/networking/sdl_net/client.cpp @@ -23,6 +23,7 @@ #define FORBIDDEN_SYMBOL_ALLOW_ALL #include "backends/networking/sdl_net/client.h" +#include "backends/networking/sdl_net/localwebserver.h" #include "common/textconsole.h" #include @@ -201,13 +202,13 @@ Common::String Client::queryParameter(Common::String name) const { } else key += _query[i]; } else { if (_query[i] == '&') { - if (key == name) return value; + if (key == name) return LocalWebserver::urlDecode(value); readingKey = true; key = ""; } else value += _query[i]; } } - if (key == name) return value; //the last key doesn't have an '&' in the end of the query + if (key == name) return LocalWebserver::urlDecode(value); //the last key doesn't have an '&' in the end of the query return ""; } diff --git a/backends/networking/sdl_net/handlers/filespagehandler.cpp b/backends/networking/sdl_net/handlers/filespagehandler.cpp index 360fe201b8..327071fc11 100644 --- a/backends/networking/sdl_net/handlers/filespagehandler.cpp +++ b/backends/networking/sdl_net/handlers/filespagehandler.cpp @@ -22,6 +22,7 @@ #include "backends/networking/sdl_net/handlers/filespagehandler.h" #include "backends/networking/sdl_net/localwebserver.h" +#include "backends/fs/fs-factory.h" #include "common/file.h" #include "common/translation.h" @@ -35,6 +36,11 @@ FilesPageHandler::FilesPageHandler() {} FilesPageHandler::~FilesPageHandler() {} void FilesPageHandler::handle(Client &client) { + if (client.path() == "/files") handleFiles(client); + else handleCreateDirectory(client); +} + +void FilesPageHandler::handleFiles(Client &client) { Common::String response = "ScummVM{content}
"; //TODO: add controls Common::String itemTemplate = "{name}{size}\n"; //TODO: load this template too? @@ -61,6 +67,8 @@ void FilesPageHandler::handle(Client &client) { //these occur twice: replace(response, "{create_directory_button}", _("Create directory")); replace(response, "{create_directory_button}", _("Create directory")); + replace(response, "{path}", client.queryParameter("path")); + replace(response, "{path}", client.queryParameter("path")); replace(response, "{upload_files_button}", _("Upload files")); //tab replace(response, "{upload_file_button}", _("Upload files")); //button in the tab replace(response, "{create_directory_desc}", _("Type new directory name:")); @@ -69,6 +77,27 @@ void FilesPageHandler::handle(Client &client) { LocalWebserver::setClientGetHandler(client, response); } +void FilesPageHandler::handleCreateDirectory(Client &client) { + Common::String path = client.queryParameter("path"); + Common::String name = client.queryParameter("directory_name"); + Common::String errorMessage = ""; + + // show an error message if failed to create directory + if (!createDirectory(path, name, errorMessage)) { + handleErrorMessage( + client, + Common::String::format( + "%s
%s", + errorMessage.c_str(), + _("Back to the files manager") + ) + ); + return; + } + + handleFiles(client); +} + void FilesPageHandler::handleErrorMessage(Client &client, Common::String message) { Common::String response = "ScummVM{message}"; @@ -80,6 +109,50 @@ void FilesPageHandler::handleErrorMessage(Client &client, Common::String message LocalWebserver::setClientGetHandler(client, response); } +bool FilesPageHandler::createDirectory(Common::String path, Common::String name, Common::String &errorMessage) { + // check that is not an absolute root + if (path == "" || path == "/") { + errorMessage = _("Can't create directory here!"); + return false; + } + + // transform virtual path to actual file system one + Common::String prefixToRemove = "", prefixToAdd = ""; + if (!transformPath(path, prefixToRemove, prefixToAdd) || path.empty()) { + errorMessage = _("Invalid path!"); + return false; + } + + // check that exists and is directory + AbstractFSNode *node = g_system->getFilesystemFactory()->makeFileNodePath(path); + if (!node->exists()) { + errorMessage = _("Parent directory doesn't exists!"); + return false; + } + if (!node->isDirectory()) { + errorMessage = _("Can't create a directory within a file!"); + return false; + } + + // check that doesn't exist or is directory + if (path.lastChar() != '/' && path.lastChar() != '\\') path += '/'; + node = g_system->getFilesystemFactory()->makeFileNodePath(path + name); + if (node->exists()) { + if (!node->isDirectory()) { + errorMessage = _("There is a file with that name in the parent directory!"); + return false; + } else return true; + } + + // create the in + if (!node->create(true)) { + errorMessage = _("Failed to create the directory!"); + return false; + } + + return true; +} + bool FilesPageHandler::listDirectory(Common::String path, Common::String &content, const Common::String &itemTemplate) { if (path == "" || path == "/") { addItem(content, itemTemplate, true, "/root/", _("File system root")); diff --git a/backends/networking/sdl_net/handlers/filespagehandler.h b/backends/networking/sdl_net/handlers/filespagehandler.h index 6205dcd52c..e5a32c98b0 100644 --- a/backends/networking/sdl_net/handlers/filespagehandler.h +++ b/backends/networking/sdl_net/handlers/filespagehandler.h @@ -29,8 +29,19 @@ namespace Networking { class FilesPageHandler: public FilesBaseHandler { void handle(Client &client); + void handleFiles(Client &client); + void handleCreateDirectory(Client &client); void handleErrorMessage(Client &client, Common::String message); + /** + * Creates the directory in . + * + * Fills on failure. + * + * Returns true on success. + */ + bool createDirectory(Common::String path, Common::String name, Common::String &errorMessage); + /** * Lists the directory . * diff --git a/backends/networking/sdl_net/localwebserver.cpp b/backends/networking/sdl_net/localwebserver.cpp index c3df9f8819..c8f322dad6 100644 --- a/backends/networking/sdl_net/localwebserver.cpp +++ b/backends/networking/sdl_net/localwebserver.cpp @@ -44,6 +44,7 @@ LocalWebserver::LocalWebserver(): _set(nullptr), _serverSocket(nullptr), _timerS _stopOnIdle(false), _clients(0), _idlingFrames(0) { addPathHandler("/", _indexPageHandler.getHandler()); addPathHandler("/files", _filesPageHandler.getHandler()); + addPathHandler("/create", _filesPageHandler.getHandler()); //"Create directory" feature _defaultHandler = _resourceHandler.getHandler(); } @@ -271,4 +272,32 @@ const char *LocalWebserver::determineMimeType(Common::String &filename) { return "application/octet-stream"; } +namespace { +int hexDigit(char c) { + if ('0' <= c && c <= '9') return c - '0'; + if ('A' <= c && c <= 'F') return c - 'A' + 10; + if ('a' <= c && c <= 'f') return c - 'a' + 10; + return -1; +} +} + +Common::String LocalWebserver::urlDecode(Common::String value) { + Common::String result = ""; + uint32 size = value.size(); + for (uint32 i = 0; i < size; ++i) { + if (value[i] == '%' && i+2 < size) { + int d1 = hexDigit(value[i+1]); + int d2 = hexDigit(value[i+2]); + if (0 <= d1 && d1 < 16 && 0 <= d2 && d2 < 16) { + result += (char)(d1 * 16 + d2); + i = i + 2; + continue; + } + } + + result += value[i]; + } + return result; +} + } // End of namespace Networking diff --git a/backends/networking/sdl_net/localwebserver.h b/backends/networking/sdl_net/localwebserver.h index 1d397e6dcc..2e56209ab0 100644 --- a/backends/networking/sdl_net/localwebserver.h +++ b/backends/networking/sdl_net/localwebserver.h @@ -87,6 +87,7 @@ public: static void setClientGetHandler(Client &client, Common::String response, long code = 200, const char *mimeType = nullptr); static void setClientGetHandler(Client &client, Common::SeekableReadStream *responseStream, long code = 200, const char *mimeType = nullptr); static const char *determineMimeType(Common::String &filename); + static Common::String urlDecode(Common::String value); }; /** Shortcut for accessing the local webserver. */ diff --git a/backends/networking/wwwroot.zip b/backends/networking/wwwroot.zip index 4d1be97524..de683a05d4 100644 Binary files a/backends/networking/wwwroot.zip and b/backends/networking/wwwroot.zip differ diff --git a/backends/networking/wwwroot/.files.html b/backends/networking/wwwroot/.files.html index 2baf4a02dc..de29ac3fa3 100644 --- a/backends/networking/wwwroot/.files.html +++ b/backends/networking/wwwroot/.files.html @@ -18,6 +18,7 @@