// Aseprite // Copyright (C) 2019-2020 Igara Studio S.A. // // This program is distributed under the terms of // the End-User License Agreement for Aseprite. #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "app/app.h" #include "app/resource_finder.h" #include "app/script/luacpp.h" #include "app/script/security.h" #include "base/fs.h" namespace app { namespace script { namespace { struct AppFS { }; int AppFS_pathSeparator(lua_State* L) { const char sep[2] = { base::path_separator, 0 }; lua_pushstring(L, sep); return 1; } template int AppFS_pathElement(lua_State* L) { const char* fn = lua_tostring(L, 1); if (fn) lua_pushstring(L, Func(fn).c_str()); else lua_pushnil(L); return 1; } int AppFS_joinPath(lua_State* L) { const char* fn = lua_tostring(L, 1); if (!fn) { lua_pushnil(L); return 1; } std::string result(fn); const int n = lua_gettop(L); for (int i=2; i<=n; ++i) { const char* part = lua_tostring(L, i); if (part) result = base::join_path(result, part); } lua_pushstring(L, result.c_str()); return 1; } template int AppFS_get_specialPath(lua_State* L) { lua_pushstring(L, Func().c_str()); return 1; } int AppFS_get_userConfigPath(lua_State* L) { ResourceFinder rf(false); rf.includeUserDir(""); std::string dir = rf.defaultFilename(); lua_pushstring(L, dir.c_str()); return 1; } int AppFS_isFile(lua_State* L) { const char* fn = lua_tostring(L, 1); if (fn) lua_pushboolean(L, base::is_file(fn)); else lua_pushboolean(L, false); return 1; } int AppFS_isDirectory(lua_State* L) { const char* fn = lua_tostring(L, 1); if (fn) lua_pushboolean(L, base::is_directory(fn)); else lua_pushboolean(L, false); return 1; } int AppFS_fileSize(lua_State* L) { const char* fn = lua_tostring(L, 1); if (fn) lua_pushinteger(L, base::file_size(fn)); else lua_pushnil(L); return 1; } int AppFS_listFiles(lua_State* L) { const char* path = lua_tostring(L, 1); lua_newtable(L); if (path) { int i = 0; for (auto fn : base::list_files(path)) { lua_pushstring(L, fn.c_str()); lua_seti(L, -2, ++i); } } return 1; } int AppFS_makeDirectory(lua_State* L) { const char* path = luaL_checkstring(L, 1); if (base::is_directory(path)) { lua_pushboolean(L, true); return 1; } if (!ask_access(L, path, FileAccessMode::Full, ResourceType::File)) return luaL_error(L, "the script doesn't have access to create the directory '%s'", path); try { // TODO don't throw exception from base::make_directory() function base::make_directory(path); } catch (const std::exception&) { // Do nothing } lua_pushboolean(L, base::is_directory(path)); return 1; } int AppFS_makeAllDirectories(lua_State* L) { const char* path = luaL_checkstring(L, 1); if (base::is_directory(path)) { lua_pushboolean(L, true); return 1; } if (!ask_access(L, path, FileAccessMode::Write, ResourceType::File)) return luaL_error(L, "the script doesn't have access to create all directories '%s'", path); try { base::make_all_directories(path); } catch (const std::exception&) { // Do nothing } lua_pushboolean(L, base::is_directory(path)); return 1; } int AppFS_removeDirectory(lua_State* L) { const char* path = luaL_checkstring(L, 1); if (!base::is_directory(path)) { lua_pushboolean(L, (base::is_file(path) ? false: // Cannot remove files true)); // The directory is already removed return 1; } if (!ask_access(L, path, FileAccessMode::Write, ResourceType::File)) return luaL_error(L, "the script doesn't have access to remove the directory '%s'", path); try { base::remove_directory(path); } catch (const std::exception&) { // do nothing... } lua_pushboolean(L, !base::is_directory(path)); return 1; } const Property AppFS_properties[] = { { "pathSeparator", AppFS_pathSeparator, nullptr }, // Special folder names { "currentPath", AppFS_get_specialPath, nullptr }, { "appPath", AppFS_get_specialPath, nullptr }, { "tempPath", AppFS_get_specialPath, nullptr }, { "userDocsPath", AppFS_get_specialPath, nullptr }, { "userConfigPath", AppFS_get_userConfigPath, nullptr }, { nullptr, nullptr, nullptr } }; const luaL_Reg AppFS_methods[] = { // Path manipulation { "filePath", AppFS_pathElement }, { "fileName", AppFS_pathElement }, { "fileExtension", AppFS_pathElement }, { "fileTitle", AppFS_pathElement }, { "filePathAndTitle", AppFS_pathElement }, { "normalizePath", AppFS_pathElement }, { "joinPath", AppFS_joinPath }, // File system information { "isFile", AppFS_isFile }, { "isDirectory", AppFS_isDirectory }, { "fileSize", AppFS_fileSize }, { "listFiles", AppFS_listFiles }, // Manipulate directories { "makeDirectory", AppFS_makeDirectory }, { "makeAllDirectories", AppFS_makeAllDirectories }, { "removeDirectory", AppFS_removeDirectory }, { nullptr, nullptr } }; } // anonymous namespace DEF_MTNAME(AppFS); void register_app_fs_object(lua_State* L) { REG_CLASS(L, AppFS); REG_CLASS_PROPERTIES(L, AppFS); lua_getglobal(L, "app"); lua_pushstring(L, "fs"); push_new(L); lua_rawset(L, -3); lua_pop(L, 1); } } // namespace script } // namespace app