├── GspotDemo ├── Gspot │ └── readme ├── conf.lua ├── lovefs │ └── readme └── main.lua ├── LICENSE ├── LoveFramesDemo ├── LoveFrames │ └── readme ├── conf.lua ├── lovefs │ └── readme └── main.lua ├── LuigiDemo ├── conf.lua ├── lovefs │ └── readme ├── luigi │ └── readme └── main.lua ├── README.md ├── lovefs-noffi ├── README.md ├── codepages │ ├── 737 │ ├── 775 │ ├── 850 │ ├── 852 │ ├── 855 │ ├── 866 │ ├── 8859-1 │ ├── 8859-15 │ ├── 8859-16 │ ├── 8859-2 │ ├── 8859-4 │ ├── 8859-5 │ ├── 8859-7 │ ├── KOI8-R │ ├── KOI8-U │ ├── code.txt │ └── main.lua ├── conf.lua ├── dialogs.lua ├── file.png ├── folder.png ├── lovefs.lua ├── main.lua └── up.png └── lovefs ├── gspotDialog.lua ├── images ├── file.png ├── folder.png └── up.png ├── loveframesDialog.lua ├── lovefs.lua ├── lovefs_linux.lua ├── lovefs_osx.lua ├── lovefs_win.lua └── luigiDialog.lua /GspotDemo/Gspot/readme: -------------------------------------------------------------------------------- 1 | Placeholder for Gspöt library (https://notabug.org/pgimeno/Gspot) 2 | -------------------------------------------------------------------------------- /GspotDemo/conf.lua: -------------------------------------------------------------------------------- 1 | function love.conf(t) 2 | t.title = "LoveFS" -- The title of the window the game is in (string) 3 | t.author = "linux-man" -- The author of the game (string) 4 | t.url = nil -- The website of the game (string) 5 | t.identity = nil -- The name of the save directory (string) 6 | t.version = "11.0" -- The LÖVE version this game was made for (string) 7 | t.console = false -- Attach a console (boolean, Windows only) 8 | t.window.width = 800 -- The window width (number) 9 | t.window.height = 600 -- The window height (number) 10 | t.window.fullscreen = false -- Enable fullscreen (boolean) 11 | t.window.vsync = true -- Enable vertical sync (boolean) 12 | t.window.fsaa = 0 -- The number of FSAA-buffers (number) 13 | t.modules.joystick = false -- Enable the joystick module (boolean) 14 | t.modules.audio = true -- Enable the audio module (boolean) 15 | t.modules.keyboard = true -- Enable the keyboard module (boolean) 16 | t.modules.event = true -- Enable the event module (boolean) 17 | t.modules.image = true -- Enable the image module (boolean) 18 | t.modules.graphics = true -- Enable the graphics module (boolean) 19 | t.modules.timer = true -- Enable the timer module (boolean) 20 | t.modules.mouse = true -- Enable the mouse module (boolean) 21 | t.modules.sound = true -- Enable the sound module (boolean) 22 | t.modules.physics = false -- Enable the physics module (boolean) 23 | end 24 | -------------------------------------------------------------------------------- /GspotDemo/lovefs/readme: -------------------------------------------------------------------------------- 1 | Placeholder for loveFS 2 | -------------------------------------------------------------------------------- /GspotDemo/main.lua: -------------------------------------------------------------------------------- 1 | gui = require('Gspot/Gspot') 2 | require('lovefs/lovefs') 3 | require('lovefs/gspotDialog') 4 | 5 | love.load = function() 6 | fs = lovefs() 7 | local button = gui:button('Load Image', {0, 0, 200, 40}) 8 | button.click = function(this) 9 | save = false 10 | fs:loadDialog(gui, 'Load Image', {'All | *.*', 'Jpeg | *.jpg *.jpeg', 'Png | *.png', 'Bmp | *.bmp', 'Gif | *.gif'}) 11 | end 12 | local button = gui:button('Load Sound', {200, 0, 200, 40}) 13 | button.click = function(this) 14 | save = false 15 | fs:loadDialog(gui, 'Load Sound', {'Sound | *.mp3 *.wav', 'All | *.*'}) 16 | end 17 | local button = gui:button('Load TrueType', {400, 0, 200, 40}) 18 | button.click = function(this) 19 | save = false 20 | fs:loadDialog(gui, 'Load TrueType', {'TrueType | *.ttf', 'All | *.*'}) 21 | end 22 | saveButton = gui:button('Save Image (as png)', {600, 0, 200, 40}) 23 | saveButton.click = function(this) 24 | save = true 25 | fs:saveDialog(gui, 'Save Image') 26 | end 27 | saveButton:hide() 28 | end 29 | 30 | love.update = function(dt) 31 | gui:update(dt) 32 | if fs.selectedFile then 33 | ext = fs.selectedFile:match('[^'..fs.sep..']+$'):match('[^.]+$') 34 | if save then 35 | if newImage then fs:saveImage(newImage) end 36 | save = false 37 | elseif ext == 'jpg' or ext == 'png' or ext == 'bmp' then 38 | newImage = fs:loadImage() 39 | saveButton:show() 40 | elseif ext == 'mp3' or ext == 'wav' then 41 | sound = fs:loadSource() 42 | sound:play() 43 | 44 | elseif ext == 'ttf' then 45 | font = fs:loadFont(32) 46 | if font then love.graphics.setFont(font) end 47 | end 48 | end 49 | end 50 | 51 | love.draw = function() 52 | love.graphics.setColor(255, 255, 255) 53 | if newImage then 54 | love.graphics.draw(newImage, 0, 0, 0, math.min(800 / newImage:getWidth(), 600 / newImage:getHeight()), math.min(800 / newImage:getWidth(), 600 / newImage:getHeight())) 55 | end 56 | love.graphics.print('LoveFS Demo', 5, 550) 57 | gui:draw() 58 | end 59 | 60 | love.mousepressed = function(x, y, button) 61 | gui:mousepress(x, y, button) 62 | end 63 | 64 | love.mousereleased = function(x, y, button) 65 | gui:mouserelease(x, y, button) 66 | end 67 | 68 | love.wheelmoved = function(x, y) 69 | gui:mousewheel(x, y) 70 | end 71 | 72 | love.keypressed = function(key) 73 | if gui.focus then 74 | gui:keypress(key) 75 | end 76 | end 77 | 78 | love.textinput = function(key) 79 | if gui.focus then 80 | gui:textinput(key) 81 | end 82 | end 83 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Caldas Lopes 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /LoveFramesDemo/LoveFrames/readme: -------------------------------------------------------------------------------- 1 | Placeholder for LoveFrames library (https://github.com/linux-man/LoveFrames) 2 | -------------------------------------------------------------------------------- /LoveFramesDemo/conf.lua: -------------------------------------------------------------------------------- 1 | function love.conf(t) 2 | t.title = "LoveFS" -- The title of the window the game is in (string) 3 | t.author = "linux-man" -- The author of the game (string) 4 | t.url = nil -- The website of the game (string) 5 | t.identity = nil -- The name of the save directory (string) 6 | t.version = "11.0" -- The LÖVE version this game was made for (string) 7 | t.console = false -- Attach a console (boolean, Windows only) 8 | t.window.width = 800 -- The window width (number) 9 | t.window.height = 600 -- The window height (number) 10 | t.window.fullscreen = false -- Enable fullscreen (boolean) 11 | t.window.vsync = true -- Enable vertical sync (boolean) 12 | t.window.fsaa = 0 -- The number of FSAA-buffers (number) 13 | t.modules.joystick = false -- Enable the joystick module (boolean) 14 | t.modules.audio = true -- Enable the audio module (boolean) 15 | t.modules.keyboard = true -- Enable the keyboard module (boolean) 16 | t.modules.event = true -- Enable the event module (boolean) 17 | t.modules.image = true -- Enable the image module (boolean) 18 | t.modules.graphics = true -- Enable the graphics module (boolean) 19 | t.modules.timer = true -- Enable the timer module (boolean) 20 | t.modules.mouse = true -- Enable the mouse module (boolean) 21 | t.modules.sound = true -- Enable the sound module (boolean) 22 | t.modules.physics = false -- Enable the physics module (boolean) 23 | end 24 | -------------------------------------------------------------------------------- /LoveFramesDemo/lovefs/readme: -------------------------------------------------------------------------------- 1 | Placeholder for loveFS 2 | -------------------------------------------------------------------------------- /LoveFramesDemo/main.lua: -------------------------------------------------------------------------------- 1 | loveframes = require("LoveFrames") 2 | require 'lovefs/lovefs' 3 | require 'lovefs/loveframesDialog' 4 | 5 | function love.load() 6 | fsload = lovefs() 7 | fssave = lovefs() 8 | 9 | btload = loveframes.Create('button', window) 10 | btload:SetPos(0,0) 11 | btload:SetSize(200, 40) 12 | btload:SetText('Load Image') 13 | btload.OnClick = function(object) 14 | fsload:loadDialog(loveframes, nil, {'All | *.*', 'Jpeg | *.jpg *.jpeg', 'Png | *.png', 'Bmp | *.bmp', 'Gif | *.gif'}) 15 | end 16 | 17 | btlsnd = loveframes.Create('button', window) 18 | btlsnd:SetPos(200,0) 19 | btlsnd:SetSize(200, 40) 20 | btlsnd:SetText('Load Sound') 21 | btlsnd.OnClick = function(object) 22 | fsload:loadDialog(loveframes, nil, {'Sound | *.mp3 *.wav', 'All | *.*'}) 23 | end 24 | 25 | btlttf = loveframes.Create('button', window) 26 | btlttf:SetPos(400,0) 27 | btlttf:SetSize(200, 40) 28 | btlttf:SetText('Load TrueType') 29 | btlttf.OnClick = function(object) 30 | fsload:loadDialog(loveframes, nil, {'TrueType | *.ttf', 'All | *.*'}) 31 | end 32 | 33 | btsave = loveframes.Create('button', window) 34 | btsave:SetPos(600,0) 35 | btsave:SetSize(200, 40) 36 | btsave:SetText('Save Image (as png)') 37 | btsave.OnClick = function(object) 38 | fssave:saveDialog(loveframes) 39 | end 40 | end 41 | 42 | function love.update(dt) 43 | if fsload.selectedFile then 44 | ext = fsload.selectedFile:match('[^'..fsload.sep..']+$'):match('[^.]+$') 45 | if ext == 'jpg' or ext == 'png' or ext == 'bmp' then 46 | newImage = fsload:loadImage() 47 | elseif ext == 'mp3' or ext == 'wav' then 48 | sound = fsload:loadSource() 49 | sound:play() 50 | elseif ext == 'ttf' then 51 | font = fsload:loadFont(32) 52 | if font then love.graphics.setFont(font) end 53 | end 54 | end 55 | btsave.visible = newImage ~= nil 56 | if fssave.selectedFile then 57 | fssave:saveImage(newImage) 58 | end 59 | loveframes.update(dt) 60 | end 61 | 62 | function love.draw() 63 | love.graphics.setColor(255, 255, 255) 64 | if newImage then 65 | love.graphics.draw(newImage, 0, 0, 0, math.min(800 / newImage:getWidth(), 600 / newImage:getHeight()), math.min(800 / newImage:getWidth(), 600 / newImage:getHeight())) 66 | end 67 | if font then love.graphics.setFont(font) end 68 | love.graphics.print('LoveFS Demo', 5, 550) 69 | loveframes.draw() 70 | end 71 | 72 | function love.mousepressed(x, y, button) 73 | loveframes.mousepressed(x, y, button) 74 | end 75 | 76 | function love.mousereleased(x, y, button) 77 | loveframes.mousereleased(x, y, button) 78 | end 79 | 80 | function love.keypressed(key, unicode) 81 | loveframes.keypressed(key, unicode) 82 | end 83 | 84 | function love.keyreleased(key, unicode) 85 | loveframes.keyreleased(key) 86 | end 87 | 88 | function love.textinput(text) 89 | loveframes.textinput(text) 90 | end 91 | -------------------------------------------------------------------------------- /LuigiDemo/conf.lua: -------------------------------------------------------------------------------- 1 | function love.conf(t) 2 | t.title = "LoveFS" -- The title of the window the game is in (string) 3 | t.author = "linux-man" -- The author of the game (string) 4 | t.url = nil -- The website of the game (string) 5 | t.identity = nil -- The name of the save directory (string) 6 | t.version = "11.0" -- The LÖVE version this game was made for (string) 7 | t.console = false -- Attach a console (boolean, Windows only) 8 | t.window.width = 800 -- The window width (number) 9 | t.window.height = 600 -- The window height (number) 10 | t.window.fullscreen = false -- Enable fullscreen (boolean) 11 | t.window.vsync = true -- Enable vertical sync (boolean) 12 | t.window.fsaa = 0 -- The number of FSAA-buffers (number) 13 | t.modules.joystick = false -- Enable the joystick module (boolean) 14 | t.modules.audio = true -- Enable the audio module (boolean) 15 | t.modules.keyboard = true -- Enable the keyboard module (boolean) 16 | t.modules.event = true -- Enable the event module (boolean) 17 | t.modules.image = true -- Enable the image module (boolean) 18 | t.modules.graphics = true -- Enable the graphics module (boolean) 19 | t.modules.timer = true -- Enable the timer module (boolean) 20 | t.modules.mouse = true -- Enable the mouse module (boolean) 21 | t.modules.sound = true -- Enable the sound module (boolean) 22 | t.modules.physics = false -- Enable the physics module (boolean) 23 | end 24 | -------------------------------------------------------------------------------- /LuigiDemo/lovefs/readme: -------------------------------------------------------------------------------- 1 | Placeholder for loveFS 2 | -------------------------------------------------------------------------------- /LuigiDemo/luigi/readme: -------------------------------------------------------------------------------- 1 | Placeholder for LUIGI library (https://github.com/airstruck/luigi) 2 | -------------------------------------------------------------------------------- /LuigiDemo/main.lua: -------------------------------------------------------------------------------- 1 | require 'lovefs/lovefs' 2 | Layout = require 'luigi.layout' 3 | require 'lovefs/luigiDialog' 4 | 5 | local layout = Layout( 6 | {flow = 'x', 7 | {style = 'btn', id = 'loadImage', text = 'Load Image'}, 8 | {style = 'btn', id = 'loadSound', text = 'Load Sound'}, 9 | {style = 'btn', id = 'loadFont', text = 'Load TrueType'}, 10 | {style = 'btn', id = 'saveImage', text = 'Save Image'}, 11 | } 12 | ) 13 | 14 | layout:setStyle( 15 | { 16 | btn = { 17 | type = 'button', 18 | width = 200, 19 | height = 48, 20 | align = 'center middle' 21 | } 22 | } 23 | ) 24 | 25 | layout.loadImage:onPress(function (event) 26 | fs:loadDialog(Layout, 'Load Image', {'All | *.*', 'Jpeg | *.jpg *.jpeg', 'Png | *.png', 'Bmp | *.bmp', 'Gif | *.gif'}) 27 | save = false 28 | end) 29 | 30 | layout.loadSound:onPress(function (event) 31 | fs:loadDialog(Layout, 'Load Sound', {'Sound | *.mp3 *.wav', 'All | *.*'}) 32 | save = false 33 | end) 34 | 35 | layout.loadFont:onPress(function (event) 36 | fs:loadDialog(Layout, 'Load TrueType', {'TrueType | *.ttf', 'All | *.*'}) 37 | save = false 38 | end) 39 | 40 | layout.saveImage:onPress(function (event) 41 | fs:saveDialog(Layout, 'Save Image') 42 | save = true 43 | end) 44 | 45 | function love.load() 46 | fs = lovefs() 47 | layout:show() 48 | layout.saveImage.width = 0 49 | end 50 | 51 | function love.update(dt) 52 | if fs.selectedFile then 53 | ext = fs.selectedFile:match('[^'..fs.sep..']+$'):match('[^.]+$') 54 | if save then 55 | if newImage then fs:saveImage(newImage) end 56 | save = false 57 | elseif ext == 'jpg' or ext == 'png' or ext == 'bmp' then 58 | newImage = fs:loadImage() 59 | layout.saveImage.width = 200 60 | elseif ext == 'mp3' or ext == 'wav' then 61 | sound = fs:loadSource() 62 | sound:play() 63 | elseif ext == 'ttf' then 64 | font = fs:loadFont(32) 65 | if font then love.graphics.setFont(font) end 66 | end 67 | end 68 | 69 | end 70 | 71 | function love.draw() 72 | love.graphics.setColor(255, 255, 255) 73 | if newImage then 74 | love.graphics.draw(newImage, 0, 0, 0, math.min(800 / newImage:getWidth(), 600 / newImage:getHeight()), math.min(800 / newImage:getWidth(), 600 / newImage:getHeight())) 75 | end 76 | love.graphics.print('LoveFS Demo', 5, 550) 77 | end 78 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # lovefs 2 | 3 | Load and save files outside `love.filesystem`. 4 | 5 | ## with ffi 6 | 7 | The ffi code was mostly adapted (with my sincerest gratitude) from 8 | 9 | * [fi-luajit](https://github.com/nyfair/fi-luajit) (Windows) 10 | * [pflua](https://github.com/Igalia/pflua) (Posix). 11 | 12 | `attr` function was adapted from 13 | * [luafilesystem-ffi](https://github.com/3scale/luafilesystem-ffi/blob/master/lfs_ffi.lua) 14 | 15 | ```lua 16 | -- dir is [string], if no dir is given, start on UserDirectory 17 | fs = lovefs(dir) 18 | ``` 19 | ## [lovefs.lua](lovefs/lovefs.lua) 20 | 21 | ### members 22 | 23 | ```lua 24 | -- Current Directory [string] (don't change it, use fs:cd(dir)) 25 | fs.current 26 | 27 | -- drives, directories and files [tables] of current dir 28 | fs.drives 29 | fs.dirs 30 | fs.files 31 | fs.others (POSIX links and devices) 32 | fs.all 33 | 34 | -- [string] used by fs:loadImage, fs:loadSource, fs:loadFont and fs:saveImage if no source is given 35 | fs.selectedFile 36 | 37 | -- user directory [string] 38 | fs.home 39 | 40 | -- [table] with extensions, like {'jpg', 'png'}. Used by fs:ls to filter files. Don't forget to NIL! 41 | fs.filter 42 | 43 | -- Show or hide hidden files and directories. Default: FALSE 44 | fs.showHidden 45 | ``` 46 | 47 | ### methods 48 | 49 | ```lua 50 | -- update drives list 51 | fs:updDrives() 52 | ``` 53 | 54 | These functions accept absolute and relative (to current) paths: 55 | 56 | ```lua 57 | -- return dir (absolute path) [string], tDirs, tFiles, tOthers, tAll [tables]. Return FALSE if dir don't exist. Alias: fs:dir(dir) 58 | fs:ls(dir) 59 | 60 | -- return TRUE if exists [boolean] 61 | fs:exists(path) 62 | 63 | -- return TRUE if is directory. [boolean] 64 | fs:isDirectory(path) 65 | 66 | -- return TRUE if is file. [boolean] 67 | fs:isFile(path) 68 | 69 | -- Change directory. Populate fs.dirs and fs.files and fs.all with the new directory contents. Return TRUE if successful 70 | fs:cd(dir) 71 | 72 | -- move to parent directory (using cd()) 73 | fs:up() 74 | 75 | -- filter can be [nil, table or string]. sets fs.filter and calls fs:cd(). 76 | -- String can be 'File type | *.ext1 *.ext2' 77 | fs:setFilter(filter) 78 | 79 | -- switch fs.showHidden 80 | fs:switchHidden() 81 | 82 | -- return absolute paths 83 | fs:absPath(path) 84 | 85 | -- return image. Use fs.selectedFile if no source is given 86 | fs:loadImage(source) 87 | 88 | --return sound. Use fs.selectedFile if no source is given 89 | fs:loadSource(source) 90 | 91 | --return font. Use fs.selectedFile if no source is given 92 | fs:loadFont(size, source) 93 | 94 | -- Need Canvas support. Return FALSE on failure. Use fs.selectedFile if no source is given 95 | fs:saveImage(img, dest) 96 | 97 | -- copy file, this function only accept absolute paths 98 | fs:copy(source, dest) 99 | 100 | -- return a table of file attributes 101 | fs:attr(path) 102 | 103 | -- return a file attribute value 104 | fs:attr(path, attr) 105 | 106 | -- (POSIX systems: follow_Symlink[boolean]) 107 | fs:attr(path, [attr or nil], follow_symlink) 108 | ``` 109 | 110 | 111 | ## dialogs 112 | 113 | These are ready-made dialogs for various UI libraries. 114 | 115 | Example filter: 116 | 117 | ```lua 118 | {'All | *.*', 'Image | *.jpg *.png *.bmp', 'Sound | *.mp3 *.wav'} 119 | ``` 120 | 121 | When the user presses OK, the selected file is available in `fs.selectedFile` 122 | 123 | ### [luigiDialog.lua](lovefs/luigiDialog.lua) 124 | 125 | Use this to make a file-browser dialog with [LUIGI](https://love2d.org/wiki/LUIGI). 126 | 127 | ```lua 128 | -- show a load dialog, without a layout 129 | fs:loadDialog(gui, label, filters) 130 | 131 | -- use with a layout 132 | fs:loadDialog(gui.Layout, label, filters) 133 | 134 | 135 | -- show a save dialog, without a layout 136 | fs:saveDialog(gui, label) 137 | 138 | -- use with a layout 139 | fs:saveDialog(gui.Layout, label) 140 | ``` 141 | 142 | ### [loveframesDialog.lua](lovefs/loveframesDialog.lua) 143 | 144 | Use this to make a file-browser dialog with [loveframes](https://github.com/linux-man/LoveFrames). 145 | 146 | ```lua 147 | -- show a load dialog 148 | fs:loadDialog(lf, label, filters) 149 | 150 | -- show a save dialog 151 | fs:saveDialog(lf, label) 152 | ``` 153 | 154 | ### [gspotDialog.lua](lovefs/gspotDialog.lua) 155 | 156 | Use this to make a file-browser dialog with [gspot](https://notabug.org/pgimeno/Gspot). 157 | 158 | ```lua 159 | -- show a load dialog 160 | fs:loadDialog(gspot, label, filters) 161 | 162 | -- show a save dialog 163 | fs:saveDialog(gspot, label) 164 | ``` 165 | 166 | ### slab 167 | 168 | [Slab](https://github.com/coding-jackalope/Slab) has some nice UI elements built-in, that use this library, as well. 169 | 170 | ### attr example 171 | ```lua 172 | require('lovefs') 173 | fs = lovefs() 174 | fs:ls() 175 | 176 | print('Current Dir:', fs.current) 177 | for key, value in pairs(fs.all) do 178 | print(key, value) 179 | t = fs:attr(fs:absPath(value)) 180 | for _, a in pairs(t) do 181 | print('\t', _, a) 182 | end 183 | print('\t', 'Human readable timestamp') 184 | print('\t', 'modification', os.date(_, tostring(t['modification'], 'atime'))) 185 | print('\t', 'access', os.date(_, tostring(t['access'], 'atime'))) 186 | print('\t', 'change', os.date(_, tostring(t['change'], 'atime'))) 187 | end 188 | 189 | -- POSIX Symlinks 190 | print('Following links') 191 | for key, value in pairs(fs.others) do 192 | print(key, value) 193 | t = fs:attr(fs:absPath(value), nil, true) 194 | for _, a in pairs(t) do 195 | print('\t', _, a) 196 | end 197 | print('\t', 'Human readable timestamp') 198 | print('\t', 'modification', os.date(_, tostring(t['modification'], 'atime'))) 199 | print('\t', 'access', os.date(_, tostring(t['access'], 'atime'))) 200 | print('\t', 'change', os.date(_, tostring(t['change'], 'atime'))) 201 | end 202 | 203 | --[[ 204 | attribs = { 205 | "access", 206 | "blksize", 207 | "blocks", 208 | "change", 209 | "dev", 210 | "gid", 211 | "ino", 212 | "mode", 213 | "modification", 214 | "nlink", 215 | "permissions", 216 | "rdev", 217 | "size", 218 | "uid"} 219 | 220 | "target" for symlinks 221 | ]]-- 222 | ``` 223 | ## without ffi 224 | 225 | You can also use [lovefs-noffi](./lovefs-noffi), if you need support for pre-ffi love2d (before love 11), or you just don't want to use FFI. It has it's own [README](lovefs-noffi/README.md). It uses `popen` to call commands from the OS, so it's a bit slower, but maybe more cross-platform, in some situations. 226 | -------------------------------------------------------------------------------- /lovefs-noffi/README.md: -------------------------------------------------------------------------------- 1 | # lovefs-noffi 2 | 3 | This is an old, unmaintained version of loveFS, hosted here for historical and affective reasons. Only usefull if there is no "ffi" access (like in the case of love pre-11.) 4 | 5 | ### Reference: 6 | 7 | ```lua 8 | -- if no dir is given, start on UserDirectory 9 | fs = lovefs(dir[string]) 10 | ``` 11 | 12 | ## [lovefs.lua](lovefs.lua) 13 | 14 | ### members 15 | 16 | ```lua 17 | -- Current Directory [string] (don't change it, use fs:cd(dir)) 18 | fs.current 19 | 20 | -- [tables] drives directories and files in current dir 21 | fs.drives 22 | fs.files 23 | fs.dirs 24 | ``` 25 | 26 | ### methods 27 | 28 | ```lua 29 | -- Used by :cd() to populate fs.dirs and fs.files 30 | fs:setParam(param) 31 | 32 | -- return file list (table and string). Alias: fs:dir(param, dir) 33 | fs:ls(param, dir) 34 | 35 | -- return drives (table) 36 | fs:lsDrives() 37 | 38 | -- return directories (table and string) 39 | fs:lsDirs(param, dir) 40 | 41 | -- return files (table and string) 42 | fs:lsFiles(param, dir) 43 | 44 | -- return TRUE if exists. 45 | fs:exists(name, dir) 46 | 47 | -- return TRUE if directory. 48 | fs:isDirectory(name, dir) 49 | 50 | -- return TRUE if is file. 51 | fs:isFile(name, dir) 52 | 53 | -- Change directory. Populate fs.dirs and fs.files with the new directory contents. 54 | -- Note: if dir is NIL current directory is used 55 | fs:cd(dir) 56 | 57 | -- same as fs:cd:('..') 58 | fs:up() 59 | 60 | -- copy file 61 | fs:copy(source, dest) 62 | 63 | -- return image 64 | fs:loadImage(source) 65 | 66 | --return sound 67 | fs:loadSource(source) 68 | 69 | --return font 70 | fs:loadFont(size, source) 71 | 72 | -- Need Canvas support. Return FALSE on failure 73 | fs:saveImage(img, dest) 74 | ``` 75 | 76 | #### internal 77 | 78 | These are for internal-use, but you might need them for something: 79 | 80 | ```lua 81 | -- Load terminal codepage. Use only for testing. Return FALSE if codepage is not supported. 82 | -- Supported codepages: '737', '775', '850', '852', '855', '866', '8859-1', '8859-2', '8859-4', '8859-5', '8859-7', '8859-15', '8859-16', 'KOI8-R', 'KOI8-U' 83 | fs:loadCp(codepage[string]) 84 | 85 | -- translate string to utf-8 86 | fs:toUtf8(str) 87 | 88 | -- translate string to current codepage 89 | fs:toCp(str) 90 | 91 | -- return Windows path in 8.3 format 92 | fs:path8p3(dir, all) 93 | 94 | -- Execute command on console 95 | fs:run(command) 96 | ``` 97 | 98 | ### [dialogs.lua](dialogs.lua) 99 | 100 | Load and Save Dialog using [loveframes](https://github.com/linux-man/LoveFrames) (modified.) 101 | 102 | ```lua 103 | -- create a load-dialog 104 | dialog = loadDialog(window_fs, filters) 105 | 106 | -- create a save-dialog 107 | dialog = saveDialog(window_fs, filters) 108 | ``` 109 | 110 | Example: 111 | 112 | ```lua 113 | fs = fsload() 114 | dialog = loadDialog(fs, {'All | *.*', 'Images | *.jpg *.bmp *.png'}) 115 | ``` 116 | 117 | On close with OK, the path of the chosen file is at `fs.selectedFile` 118 | -------------------------------------------------------------------------------- /lovefs-noffi/codepages/737: -------------------------------------------------------------------------------- 1 | \206\145 2 | \206\146 3 | \206\147 4 | \206\148 5 | \206\149 6 | \206\150 7 | \206\151 8 | \206\152 9 | \206\153 10 | \206\154 11 | \206\155 12 | \206\156 13 | \206\157 14 | \206\158 15 | \206\159 16 | \206\160 17 | \206\161 18 | \206\163 19 | \206\164 20 | \206\165 21 | \206\166 22 | \206\167 23 | \206\168 24 | \206\169 25 | \206\177 26 | \206\178 27 | \206\179 28 | \206\180 29 | \206\181 30 | \206\182 31 | \206\183 32 | \206\184 33 | \206\185 34 | \206\186 35 | \206\187 36 | \206\188 37 | \206\189 38 | \206\190 39 | \206\191 40 | \207\128 41 | \207\129 42 | \207\131 43 | \207\130 44 | \207\132 45 | \207\133 46 | \207\134 47 | \207\135 48 | \207\136 49 | \226\150\145 50 | \226\150\146 51 | \226\150\147 52 | \226\148\130 53 | \226\148\164 54 | \226\149\161 55 | \226\149\162 56 | \226\149\150 57 | \226\149\149 58 | \226\149\163 59 | \226\149\145 60 | \226\149\151 61 | \226\149\157 62 | \226\149\156 63 | \226\149\155 64 | \226\148\144 65 | \226\148\148 66 | \226\148\180 67 | \226\148\172 68 | \226\148\156 69 | \226\148\128 70 | \226\148\188 71 | \226\149\158 72 | \226\149\159 73 | \226\149\154 74 | \226\149\148 75 | \226\149\169 76 | \226\149\166 77 | \226\149\160 78 | \226\149\144 79 | \226\149\172 80 | \226\149\167 81 | \226\149\168 82 | \226\149\164 83 | \226\149\165 84 | \226\149\153 85 | \226\149\152 86 | \226\149\146 87 | \226\149\147 88 | \226\149\171 89 | \226\149\170 90 | \226\148\152 91 | \226\148\140 92 | \226\150\136 93 | \226\150\132 94 | \226\150\140 95 | \226\150\144 96 | \226\150\128 97 | \207\137 98 | \206\172 99 | \206\173 100 | \206\174 101 | \207\138 102 | \206\175 103 | \207\140 104 | \207\141 105 | \207\139 106 | \207\142 107 | \206\134 108 | \206\136 109 | \206\137 110 | \206\138 111 | \206\140 112 | \206\142 113 | \206\143 114 | \194\177 115 | \226\137\165 116 | \226\137\164 117 | \206\170 118 | \206\171 119 | \195\183 120 | \226\137\136 121 | \194\176 122 | \226\136\153 123 | \194\183 124 | \226\136\154 125 | \226\129\191 126 | \194\178 127 | \226\150\160 128 | \194\160 129 | -------------------------------------------------------------------------------- /lovefs-noffi/codepages/775: -------------------------------------------------------------------------------- 1 | \196\134 2 | \195\188 3 | \195\169 4 | \196\129 5 | \195\164 6 | \196\163 7 | \195\165 8 | \196\135 9 | \197\130 10 | \196\147 11 | \197\150 12 | \197\151 13 | \196\171 14 | \197\185 15 | \195\132 16 | \195\133 17 | \195\137 18 | \195\166 19 | \195\134 20 | \197\141 21 | \195\182 22 | \196\162 23 | \194\162 24 | \197\154 25 | \197\155 26 | \195\150 27 | \195\156 28 | \195\184 29 | \194\163 30 | \195\152 31 | \195\151 32 | \194\164 33 | \196\128 34 | \196\170 35 | \195\179 36 | \197\187 37 | \197\188 38 | \197\186 39 | \226\128\157 40 | \194\166 41 | \194\169 42 | \194\174 43 | \194\172 44 | \194\189 45 | \194\188 46 | \197\129 47 | \194\171 48 | \194\187 49 | \226\150\145 50 | \226\150\146 51 | \226\150\147 52 | \226\148\130 53 | \226\148\164 54 | \196\132 55 | \196\140 56 | \196\152 57 | \196\150 58 | \226\149\163 59 | \226\149\145 60 | \226\149\151 61 | \226\149\157 62 | \196\174 63 | \197\160 64 | \226\148\144 65 | \226\148\148 66 | \226\148\180 67 | \226\148\172 68 | \226\148\156 69 | \226\148\128 70 | \226\148\188 71 | \197\178 72 | \197\170 73 | \226\149\154 74 | \226\149\148 75 | \226\149\169 76 | \226\149\166 77 | \226\149\160 78 | \226\149\144 79 | \226\149\172 80 | \197\189 81 | \196\133 82 | \196\141 83 | \196\153 84 | \196\151 85 | \196\175 86 | \197\161 87 | \197\179 88 | \197\171 89 | \197\190 90 | \226\148\152 91 | \226\148\140 92 | \226\150\136 93 | \226\150\132 94 | \226\150\140 95 | \226\150\144 96 | \226\150\128 97 | \195\147 98 | \195\159 99 | \197\140 100 | \197\131 101 | \195\181 102 | \195\149 103 | \194\181 104 | \197\132 105 | \196\182 106 | \196\183 107 | \196\187 108 | \196\188 109 | \197\134 110 | \196\146 111 | \197\133 112 | \226\128\153 113 | \194\173 114 | \194\177 115 | \226\128\156 116 | \194\190 117 | \194\182 118 | \194\167 119 | \195\183 120 | \226\128\158 121 | \194\176 122 | \226\136\153 123 | \194\183 124 | \194\185 125 | \194\179 126 | \194\178 127 | \226\150\160 128 | \194\160 129 | -------------------------------------------------------------------------------- /lovefs-noffi/codepages/850: -------------------------------------------------------------------------------- 1 | \195\135 2 | \195\188 3 | \195\169 4 | \195\162 5 | \195\164 6 | \195\160 7 | \195\165 8 | \195\167 9 | \195\170 10 | \195\171 11 | \195\168 12 | \195\175 13 | \195\174 14 | \195\172 15 | \195\132 16 | \195\133 17 | \195\137 18 | \195\166 19 | \195\134 20 | \195\180 21 | \195\182 22 | \195\178 23 | \195\187 24 | \195\185 25 | \195\191 26 | \195\150 27 | \195\156 28 | \195\184 29 | \194\163 30 | \195\152 31 | \195\151 32 | \198\146 33 | \195\161 34 | \195\173 35 | \195\179 36 | \195\186 37 | \195\177 38 | \195\145 39 | \194\170 40 | \194\186 41 | \194\191 42 | \194\174 43 | \194\172 44 | \194\189 45 | \194\188 46 | \194\161 47 | \194\171 48 | \194\187 49 | \226\150\145 50 | \226\150\146 51 | \226\150\147 52 | \226\148\130 53 | \226\148\164 54 | \195\129 55 | \195\130 56 | \195\128 57 | \194\169 58 | \226\149\163 59 | \226\149\145 60 | \226\149\151 61 | \226\149\157 62 | \194\162 63 | \194\165 64 | \226\148\144 65 | \226\148\148 66 | \226\148\180 67 | \226\148\172 68 | \226\148\156 69 | \226\148\128 70 | \226\148\188 71 | \195\163 72 | \195\131 73 | \226\149\154 74 | \226\149\148 75 | \226\149\169 76 | \226\149\166 77 | \226\149\160 78 | \226\149\144 79 | \226\149\172 80 | \194\164 81 | \195\176 82 | \195\144 83 | \195\138 84 | \195\139 85 | \195\136 86 | \196\177 87 | \195\141 88 | \195\142 89 | \195\143 90 | \226\148\152 91 | \226\148\140 92 | \226\150\136 93 | \226\150\132 94 | \194\166 95 | \195\140 96 | \226\150\128 97 | \195\147 98 | \195\159 99 | \195\148 100 | \195\146 101 | \195\181 102 | \195\149 103 | \194\181 104 | \195\190 105 | \195\158 106 | \195\154 107 | \195\155 108 | \195\153 109 | \195\189 110 | \195\157 111 | \194\175 112 | \194\180 113 | \194\173 114 | \194\177 115 | \226\128\151 116 | \194\190 117 | \194\182 118 | \194\167 119 | \195\183 120 | \194\184 121 | \194\176 122 | \194\168 123 | \194\183 124 | \194\185 125 | \194\179 126 | \194\178 127 | \226\150\160 128 | \194\160 129 | -------------------------------------------------------------------------------- /lovefs-noffi/codepages/852: -------------------------------------------------------------------------------- 1 | \195\135 2 | \195\188 3 | \195\169 4 | \195\162 5 | \195\164 6 | \197\175 7 | \196\135 8 | \195\167 9 | \197\130 10 | \195\171 11 | \197\144 12 | \197\145 13 | \195\174 14 | \197\185 15 | \195\132 16 | \196\134 17 | \195\137 18 | \196\185 19 | \196\186 20 | \195\180 21 | \195\182 22 | \196\189 23 | \196\190 24 | \197\154 25 | \197\155 26 | \195\150 27 | \195\156 28 | \197\164 29 | \197\165 30 | \197\129 31 | \195\151 32 | \196\141 33 | \195\161 34 | \195\173 35 | \195\179 36 | \195\186 37 | \196\132 38 | \196\133 39 | \197\189 40 | \197\190 41 | \196\152 42 | \196\153 43 | \194\172 44 | \197\186 45 | \196\140 46 | \197\159 47 | \194\171 48 | \194\187 49 | \226\150\145 50 | \226\150\146 51 | \226\150\147 52 | \226\148\130 53 | \226\148\164 54 | \195\129 55 | \195\130 56 | \196\154 57 | \197\158 58 | \226\149\163 59 | \226\149\145 60 | \226\149\151 61 | \226\149\157 62 | \197\187 63 | \197\188 64 | \226\148\144 65 | \226\148\148 66 | \226\148\180 67 | \226\148\172 68 | \226\148\156 69 | \226\148\128 70 | \226\148\188 71 | \196\130 72 | \196\131 73 | \226\149\154 74 | \226\149\148 75 | \226\149\169 76 | \226\149\166 77 | \226\149\160 78 | \226\149\144 79 | \226\149\172 80 | \194\164 81 | \196\145 82 | \196\144 83 | \196\142 84 | \195\139 85 | \196\143 86 | \197\135 87 | \195\141 88 | \195\142 89 | \196\155 90 | \226\148\152 91 | \226\148\140 92 | \226\150\136 93 | \226\150\132 94 | \197\162 95 | \197\174 96 | \226\150\128 97 | \195\147 98 | \195\159 99 | \195\148 100 | \197\131 101 | \197\132 102 | \197\136 103 | \197\160 104 | \197\161 105 | \197\148 106 | \195\154 107 | \197\149 108 | \197\176 109 | \195\189 110 | \195\157 111 | \197\163 112 | \194\180 113 | \194\173 114 | \203\157 115 | \203\155 116 | \203\135 117 | \203\152 118 | \194\167 119 | \195\183 120 | \194\184 121 | \194\176 122 | \194\168 123 | \203\153 124 | \197\177 125 | \197\152 126 | \197\153 127 | \226\150\160 128 | \194\160 129 | -------------------------------------------------------------------------------- /lovefs-noffi/codepages/855: -------------------------------------------------------------------------------- 1 | \209\146 2 | \208\130 3 | \209\147 4 | \208\131 5 | \209\145 6 | \208\129 7 | \209\148 8 | \208\132 9 | \209\149 10 | \208\133 11 | \209\150 12 | \208\134 13 | \209\151 14 | \208\135 15 | \209\152 16 | \208\136 17 | \209\153 18 | \208\137 19 | \209\154 20 | \208\138 21 | \209\155 22 | \208\139 23 | \209\156 24 | \208\140 25 | \209\158 26 | \208\142 27 | \209\159 28 | \208\143 29 | \209\142 30 | \208\174 31 | \209\138 32 | \208\170 33 | \208\176 34 | \208\144 35 | \208\177 36 | \208\145 37 | \209\134 38 | \208\166 39 | \208\180 40 | \208\148 41 | \208\181 42 | \208\149 43 | \209\132 44 | \208\164 45 | \208\179 46 | \208\147 47 | \194\171 48 | \194\187 49 | \226\150\145 50 | \226\150\146 51 | \226\150\147 52 | \226\148\130 53 | \226\148\164 54 | \209\133 55 | \208\165 56 | \208\184 57 | \208\152 58 | \226\149\163 59 | \226\149\145 60 | \226\149\151 61 | \226\149\157 62 | \208\185 63 | \208\153 64 | \226\148\144 65 | \226\148\148 66 | \226\148\180 67 | \226\148\172 68 | \226\148\156 69 | \226\148\128 70 | \226\148\188 71 | \208\186 72 | \208\154 73 | \226\149\154 74 | \226\149\148 75 | \226\149\169 76 | \226\149\166 77 | \226\149\160 78 | \226\149\144 79 | \226\149\172 80 | \194\164 81 | \208\187 82 | \208\155 83 | \208\188 84 | \208\156 85 | \208\189 86 | \208\157 87 | \208\190 88 | \208\158 89 | \208\191 90 | \226\148\152 91 | \226\148\140 92 | \226\150\136 93 | \226\150\132 94 | \208\159 95 | \209\143 96 | \226\150\128 97 | \208\175 98 | \209\128 99 | \208\160 100 | \209\129 101 | \208\161 102 | \209\130 103 | \208\162 104 | \209\131 105 | \208\163 106 | \208\182 107 | \208\150 108 | \208\178 109 | \208\146 110 | \209\140 111 | \208\172 112 | \226\132\150 113 | \194\173 114 | \209\139 115 | \208\171 116 | \208\183 117 | \208\151 118 | \209\136 119 | \208\168 120 | \209\141 121 | \208\173 122 | \209\137 123 | \208\169 124 | \209\135 125 | \208\167 126 | \194\167 127 | \226\150\160 128 | \194\160 129 | -------------------------------------------------------------------------------- /lovefs-noffi/codepages/866: -------------------------------------------------------------------------------- 1 | \208\144 2 | \208\145 3 | \208\146 4 | \208\147 5 | \208\148 6 | \208\149 7 | \208\150 8 | \208\151 9 | \208\152 10 | \208\153 11 | \208\154 12 | \208\155 13 | \208\156 14 | \208\157 15 | \208\158 16 | \208\159 17 | \208\160 18 | \208\161 19 | \208\162 20 | \208\163 21 | \208\164 22 | \208\165 23 | \208\166 24 | \208\167 25 | \208\168 26 | \208\169 27 | \208\170 28 | \208\171 29 | \208\172 30 | \208\173 31 | \208\174 32 | \208\175 33 | \208\176 34 | \208\177 35 | \208\178 36 | \208\179 37 | \208\180 38 | \208\181 39 | \208\182 40 | \208\183 41 | \208\184 42 | \208\185 43 | \208\186 44 | \208\187 45 | \208\188 46 | \208\189 47 | \208\190 48 | \208\191 49 | \226\150\145 50 | \226\150\146 51 | \226\150\147 52 | \226\148\130 53 | \226\148\164 54 | \226\149\161 55 | \226\149\162 56 | \226\149\150 57 | \226\149\149 58 | \226\149\163 59 | \226\149\145 60 | \226\149\151 61 | \226\149\157 62 | \226\149\156 63 | \226\149\155 64 | \226\148\144 65 | \226\148\148 66 | \226\148\180 67 | \226\148\172 68 | \226\148\156 69 | \226\148\128 70 | \226\148\188 71 | \226\149\158 72 | \226\149\159 73 | \226\149\154 74 | \226\149\148 75 | \226\149\169 76 | \226\149\166 77 | \226\149\160 78 | \226\149\144 79 | \226\149\172 80 | \226\149\167 81 | \226\149\168 82 | \226\149\164 83 | \226\149\165 84 | \226\149\153 85 | \226\149\152 86 | \226\149\146 87 | \226\149\147 88 | \226\149\171 89 | \226\149\170 90 | \226\148\152 91 | \226\148\140 92 | \226\150\136 93 | \226\150\132 94 | \226\150\140 95 | \226\150\144 96 | \226\150\128 97 | \209\128 98 | \209\129 99 | \209\130 100 | \209\131 101 | \209\132 102 | \209\133 103 | \209\134 104 | \209\135 105 | \209\136 106 | \209\137 107 | \209\138 108 | \209\139 109 | \209\140 110 | \209\141 111 | \209\142 112 | \209\143 113 | \208\129 114 | \209\145 115 | \208\132 116 | \209\148 117 | \208\135 118 | \209\151 119 | \208\142 120 | \209\158 121 | \194\176 122 | \226\136\153 123 | \194\183 124 | \226\136\154 125 | \226\132\150 126 | \194\164 127 | \226\150\160 128 | \194\160 129 | -------------------------------------------------------------------------------- /lovefs-noffi/codepages/8859-1: -------------------------------------------------------------------------------- 1 | \194\128 2 | \194\129 3 | \194\130 4 | \194\131 5 | \194\132 6 | \194\133 7 | \194\134 8 | \194\135 9 | \194\136 10 | \194\137 11 | \194\138 12 | \194\139 13 | \194\140 14 | \194\141 15 | \194\142 16 | \194\143 17 | \194\144 18 | \194\145 19 | \194\146 20 | \194\147 21 | \194\148 22 | \194\149 23 | \194\150 24 | \194\151 25 | \194\152 26 | \194\153 27 | \194\154 28 | \194\155 29 | \194\156 30 | \194\157 31 | \194\158 32 | \194\159 33 | \194\160 34 | \194\161 35 | \194\162 36 | \194\163 37 | \194\164 38 | \194\165 39 | \194\166 40 | \194\167 41 | \194\168 42 | \194\169 43 | \194\170 44 | \194\171 45 | \194\172 46 | \194\173 47 | \194\174 48 | \194\175 49 | \194\176 50 | \194\177 51 | \194\178 52 | \194\179 53 | \194\180 54 | \194\181 55 | \194\182 56 | \194\183 57 | \194\184 58 | \194\185 59 | \194\186 60 | \194\187 61 | \194\188 62 | \194\189 63 | \194\190 64 | \194\191 65 | \195\128 66 | \195\129 67 | \195\130 68 | \195\131 69 | \195\132 70 | \195\133 71 | \195\134 72 | \195\135 73 | \195\136 74 | \195\137 75 | \195\138 76 | \195\139 77 | \195\140 78 | \195\141 79 | \195\142 80 | \195\143 81 | \195\144 82 | \195\145 83 | \195\146 84 | \195\147 85 | \195\148 86 | \195\149 87 | \195\150 88 | \195\151 89 | \195\152 90 | \195\153 91 | \195\154 92 | \195\155 93 | \195\156 94 | \195\157 95 | \195\158 96 | \195\159 97 | \195\160 98 | \195\161 99 | \195\162 100 | \195\163 101 | \195\164 102 | \195\165 103 | \195\166 104 | \195\167 105 | \195\168 106 | \195\169 107 | \195\170 108 | \195\171 109 | \195\172 110 | \195\173 111 | \195\174 112 | \195\175 113 | \195\176 114 | \195\177 115 | \195\178 116 | \195\179 117 | \195\180 118 | \195\181 119 | \195\182 120 | \195\183 121 | \195\184 122 | \195\185 123 | \195\186 124 | \195\187 125 | \195\188 126 | \195\189 127 | \195\190 128 | \195\191 129 | -------------------------------------------------------------------------------- /lovefs-noffi/codepages/8859-15: -------------------------------------------------------------------------------- 1 | \194\128 2 | \194\129 3 | \194\130 4 | \194\131 5 | \194\132 6 | \194\133 7 | \194\134 8 | \194\135 9 | \194\136 10 | \194\137 11 | \194\138 12 | \194\139 13 | \194\140 14 | \194\141 15 | \194\142 16 | \194\143 17 | \194\144 18 | \194\145 19 | \194\146 20 | \194\147 21 | \194\148 22 | \194\149 23 | \194\150 24 | \194\151 25 | \194\152 26 | \194\153 27 | \194\154 28 | \194\155 29 | \194\156 30 | \194\157 31 | \194\158 32 | \194\159 33 | \194\160 34 | \194\161 35 | \194\162 36 | \194\163 37 | \226\130\172 38 | \194\165 39 | \197\160 40 | \194\167 41 | \197\161 42 | \194\169 43 | \194\170 44 | \194\171 45 | \194\172 46 | \194\173 47 | \194\174 48 | \194\175 49 | \194\176 50 | \194\177 51 | \194\178 52 | \194\179 53 | \197\189 54 | \194\181 55 | \194\182 56 | \194\183 57 | \197\190 58 | \194\185 59 | \194\186 60 | \194\187 61 | \197\146 62 | \197\147 63 | \197\184 64 | \194\191 65 | \195\128 66 | \195\129 67 | \195\130 68 | \195\131 69 | \195\132 70 | \195\133 71 | \195\134 72 | \195\135 73 | \195\136 74 | \195\137 75 | \195\138 76 | \195\139 77 | \195\140 78 | \195\141 79 | \195\142 80 | \195\143 81 | \195\144 82 | \195\145 83 | \195\146 84 | \195\147 85 | \195\148 86 | \195\149 87 | \195\150 88 | \195\151 89 | \195\152 90 | \195\153 91 | \195\154 92 | \195\155 93 | \195\156 94 | \195\157 95 | \195\158 96 | \195\159 97 | \195\160 98 | \195\161 99 | \195\162 100 | \195\163 101 | \195\164 102 | \195\165 103 | \195\166 104 | \195\167 105 | \195\168 106 | \195\169 107 | \195\170 108 | \195\171 109 | \195\172 110 | \195\173 111 | \195\174 112 | \195\175 113 | \195\176 114 | \195\177 115 | \195\178 116 | \195\179 117 | \195\180 118 | \195\181 119 | \195\182 120 | \195\183 121 | \195\184 122 | \195\185 123 | \195\186 124 | \195\187 125 | \195\188 126 | \195\189 127 | \195\190 128 | \195\191 129 | -------------------------------------------------------------------------------- /lovefs-noffi/codepages/8859-16: -------------------------------------------------------------------------------- 1 | \194\128 2 | \194\129 3 | \194\130 4 | \194\131 5 | \194\132 6 | \194\133 7 | \194\134 8 | \194\135 9 | \194\136 10 | \194\137 11 | \194\138 12 | \194\139 13 | \194\140 14 | \194\141 15 | \194\142 16 | \194\143 17 | \194\144 18 | \194\145 19 | \194\146 20 | \194\147 21 | \194\148 22 | \194\149 23 | \194\150 24 | \194\151 25 | \194\152 26 | \194\153 27 | \194\154 28 | \194\155 29 | \194\156 30 | \194\157 31 | \194\158 32 | \194\159 33 | \194\160 34 | \196\132 35 | \196\133 36 | \197\129 37 | \226\130\172 38 | \226\128\158 39 | \197\160 40 | \194\167 41 | \197\161 42 | \194\169 43 | \200\152 44 | \194\171 45 | \197\185 46 | \194\173 47 | \197\186 48 | \197\187 49 | \194\176 50 | \194\177 51 | \196\140 52 | \197\130 53 | \197\189 54 | \226\128\157 55 | \194\182 56 | \194\183 57 | \197\190 58 | \196\141 59 | \200\153 60 | \194\187 61 | \197\146 62 | \197\147 63 | \197\184 64 | \197\188 65 | \195\128 66 | \195\129 67 | \195\130 68 | \196\130 69 | \195\132 70 | \196\134 71 | \195\134 72 | \195\135 73 | \195\136 74 | \195\137 75 | \195\138 76 | \195\139 77 | \195\140 78 | \195\141 79 | \195\142 80 | \195\143 81 | \196\144 82 | \197\131 83 | \195\146 84 | \195\147 85 | \195\148 86 | \197\144 87 | \195\150 88 | \197\154 89 | \197\176 90 | \195\153 91 | \195\154 92 | \195\155 93 | \195\156 94 | \196\152 95 | \200\154 96 | \195\159 97 | \195\160 98 | \195\161 99 | \195\162 100 | \196\131 101 | \195\164 102 | \196\135 103 | \195\166 104 | \195\167 105 | \195\168 106 | \195\169 107 | \195\170 108 | \195\171 109 | \195\172 110 | \195\173 111 | \195\174 112 | \195\175 113 | \196\145 114 | \197\132 115 | \195\178 116 | \195\179 117 | \195\180 118 | \197\145 119 | \195\182 120 | \197\155 121 | \197\177 122 | \195\185 123 | \195\186 124 | \195\187 125 | \195\188 126 | \196\153 127 | \200\155 128 | \195\191 129 | -------------------------------------------------------------------------------- /lovefs-noffi/codepages/8859-2: -------------------------------------------------------------------------------- 1 | \194\128 2 | \194\129 3 | \194\130 4 | \194\131 5 | \194\132 6 | \194\133 7 | \194\134 8 | \194\135 9 | \194\136 10 | \194\137 11 | \194\138 12 | \194\139 13 | \194\140 14 | \194\141 15 | \194\142 16 | \194\143 17 | \194\144 18 | \194\145 19 | \194\146 20 | \194\147 21 | \194\148 22 | \194\149 23 | \194\150 24 | \194\151 25 | \194\152 26 | \194\153 27 | \194\154 28 | \194\155 29 | \194\156 30 | \194\157 31 | \194\158 32 | \194\159 33 | \194\160 34 | \196\132 35 | \203\152 36 | \197\129 37 | \194\164 38 | \196\189 39 | \197\154 40 | \194\167 41 | \194\168 42 | \197\160 43 | \197\158 44 | \197\164 45 | \197\185 46 | \194\173 47 | \197\189 48 | \197\187 49 | \194\176 50 | \196\133 51 | \203\155 52 | \197\130 53 | \194\180 54 | \196\190 55 | \197\155 56 | \203\135 57 | \194\184 58 | \197\161 59 | \197\159 60 | \197\165 61 | \197\186 62 | \203\157 63 | \197\190 64 | \197\188 65 | \197\148 66 | \195\129 67 | \195\130 68 | \196\130 69 | \195\132 70 | \196\185 71 | \196\134 72 | \195\135 73 | \196\140 74 | \195\137 75 | \196\152 76 | \195\139 77 | \196\154 78 | \195\141 79 | \195\142 80 | \196\142 81 | \196\144 82 | \197\131 83 | \197\135 84 | \195\147 85 | \195\148 86 | \197\144 87 | \195\150 88 | \195\151 89 | \197\152 90 | \197\174 91 | \195\154 92 | \197\176 93 | \195\156 94 | \195\157 95 | \197\162 96 | \195\159 97 | \197\149 98 | \195\161 99 | \195\162 100 | \196\131 101 | \195\164 102 | \196\186 103 | \196\135 104 | \195\167 105 | \196\141 106 | \195\169 107 | \196\153 108 | \195\171 109 | \196\155 110 | \195\173 111 | \195\174 112 | \196\143 113 | \196\145 114 | \197\132 115 | \197\136 116 | \195\179 117 | \195\180 118 | \197\145 119 | \195\182 120 | \195\183 121 | \197\153 122 | \197\175 123 | \195\186 124 | \197\177 125 | \195\188 126 | \195\189 127 | \197\163 128 | \203\153 129 | -------------------------------------------------------------------------------- /lovefs-noffi/codepages/8859-4: -------------------------------------------------------------------------------- 1 | \194\128 2 | \194\129 3 | \194\130 4 | \194\131 5 | \194\132 6 | \194\133 7 | \194\134 8 | \194\135 9 | \194\136 10 | \194\137 11 | \194\138 12 | \194\139 13 | \194\140 14 | \194\141 15 | \194\142 16 | \194\143 17 | \194\144 18 | \194\145 19 | \194\146 20 | \194\147 21 | \194\148 22 | \194\149 23 | \194\150 24 | \194\151 25 | \194\152 26 | \194\153 27 | \194\154 28 | \194\155 29 | \194\156 30 | \194\157 31 | \194\158 32 | \194\159 33 | \194\160 34 | \196\132 35 | \196\184 36 | \197\150 37 | \194\164 38 | \196\168 39 | \196\187 40 | \194\167 41 | \194\168 42 | \197\160 43 | \196\146 44 | \196\162 45 | \197\166 46 | \194\173 47 | \197\189 48 | \194\175 49 | \194\176 50 | \196\133 51 | \203\155 52 | \197\151 53 | \194\180 54 | \196\169 55 | \196\188 56 | \203\135 57 | \194\184 58 | \197\161 59 | \196\147 60 | \196\163 61 | \197\167 62 | \197\138 63 | \197\190 64 | \197\139 65 | \196\128 66 | \195\129 67 | \195\130 68 | \195\131 69 | \195\132 70 | \195\133 71 | \195\134 72 | \196\174 73 | \196\140 74 | \195\137 75 | \196\152 76 | \195\139 77 | \196\150 78 | \195\141 79 | \195\142 80 | \196\170 81 | \196\144 82 | \197\133 83 | \197\140 84 | \196\182 85 | \195\148 86 | \195\149 87 | \195\150 88 | \195\151 89 | \195\152 90 | \197\178 91 | \195\154 92 | \195\155 93 | \195\156 94 | \197\168 95 | \197\170 96 | \195\159 97 | \196\129 98 | \195\161 99 | \195\162 100 | \195\163 101 | \195\164 102 | \195\165 103 | \195\166 104 | \196\175 105 | \196\141 106 | \195\169 107 | \196\153 108 | \195\171 109 | \196\151 110 | \195\173 111 | \195\174 112 | \196\171 113 | \196\145 114 | \197\134 115 | \197\141 116 | \196\183 117 | \195\180 118 | \195\181 119 | \195\182 120 | \195\183 121 | \195\184 122 | \197\179 123 | \195\186 124 | \195\187 125 | \195\188 126 | \197\169 127 | \197\171 128 | \203\153 129 | -------------------------------------------------------------------------------- /lovefs-noffi/codepages/8859-5: -------------------------------------------------------------------------------- 1 | \194\128 2 | \194\129 3 | \194\130 4 | \194\131 5 | \194\132 6 | \194\133 7 | \194\134 8 | \194\135 9 | \194\136 10 | \194\137 11 | \194\138 12 | \194\139 13 | \194\140 14 | \194\141 15 | \194\142 16 | \194\143 17 | \194\144 18 | \194\145 19 | \194\146 20 | \194\147 21 | \194\148 22 | \194\149 23 | \194\150 24 | \194\151 25 | \194\152 26 | \194\153 27 | \194\154 28 | \194\155 29 | \194\156 30 | \194\157 31 | \194\158 32 | \194\159 33 | \194\160 34 | \208\129 35 | \208\130 36 | \208\131 37 | \208\132 38 | \208\133 39 | \208\134 40 | \208\135 41 | \208\136 42 | \208\137 43 | \208\138 44 | \208\139 45 | \208\140 46 | \194\173 47 | \208\142 48 | \208\143 49 | \208\144 50 | \208\145 51 | \208\146 52 | \208\147 53 | \208\148 54 | \208\149 55 | \208\150 56 | \208\151 57 | \208\152 58 | \208\153 59 | \208\154 60 | \208\155 61 | \208\156 62 | \208\157 63 | \208\158 64 | \208\159 65 | \208\160 66 | \208\161 67 | \208\162 68 | \208\163 69 | \208\164 70 | \208\165 71 | \208\166 72 | \208\167 73 | \208\168 74 | \208\169 75 | \208\170 76 | \208\171 77 | \208\172 78 | \208\173 79 | \208\174 80 | \208\175 81 | \208\176 82 | \208\177 83 | \208\178 84 | \208\179 85 | \208\180 86 | \208\181 87 | \208\182 88 | \208\183 89 | \208\184 90 | \208\185 91 | \208\186 92 | \208\187 93 | \208\188 94 | \208\189 95 | \208\190 96 | \208\191 97 | \209\128 98 | \209\129 99 | \209\130 100 | \209\131 101 | \209\132 102 | \209\133 103 | \209\134 104 | \209\135 105 | \209\136 106 | \209\137 107 | \209\138 108 | \209\139 109 | \209\140 110 | \209\141 111 | \209\142 112 | \209\143 113 | \226\132\150 114 | \209\145 115 | \209\146 116 | \209\147 117 | \209\148 118 | \209\149 119 | \209\150 120 | \209\151 121 | \209\152 122 | \209\153 123 | \209\154 124 | \209\155 125 | \209\156 126 | \194\167 127 | \209\158 128 | \209\159 129 | -------------------------------------------------------------------------------- /lovefs-noffi/codepages/8859-7: -------------------------------------------------------------------------------- 1 | \194\128 2 | \194\129 3 | \194\130 4 | \194\131 5 | \194\132 6 | \194\133 7 | \194\134 8 | \194\135 9 | \194\136 10 | \194\137 11 | \194\138 12 | \194\139 13 | \194\140 14 | \194\141 15 | \194\142 16 | \194\143 17 | \194\144 18 | \194\145 19 | \194\146 20 | \194\147 21 | \194\148 22 | \194\149 23 | \194\150 24 | \194\151 25 | \194\152 26 | \194\153 27 | \194\154 28 | \194\155 29 | \194\156 30 | \194\157 31 | \194\158 32 | \194\159 33 | \194\160 34 | \226\128\152 35 | \226\128\153 36 | \194\163 37 | \226\130\172 38 | \226\130\175 39 | \194\166 40 | \194\167 41 | \194\168 42 | \194\169 43 | \205\186 44 | \194\171 45 | \194\172 46 | \194\173 47 | 48 | \226\128\149 49 | \194\176 50 | \194\177 51 | \194\178 52 | \194\179 53 | \206\132 54 | \206\133 55 | \206\134 56 | \194\183 57 | \206\136 58 | \206\137 59 | \206\138 60 | \194\187 61 | \206\140 62 | \194\189 63 | \206\142 64 | \206\143 65 | \206\144 66 | \206\145 67 | \206\146 68 | \206\147 69 | \206\148 70 | \206\149 71 | \206\150 72 | \206\151 73 | \206\152 74 | \206\153 75 | \206\154 76 | \206\155 77 | \206\156 78 | \206\157 79 | \206\158 80 | \206\159 81 | \206\160 82 | \206\161 83 | 84 | \206\163 85 | \206\164 86 | \206\165 87 | \206\166 88 | \206\167 89 | \206\168 90 | \206\169 91 | \206\170 92 | \206\171 93 | \206\172 94 | \206\173 95 | \206\174 96 | \206\175 97 | \206\176 98 | \206\177 99 | \206\178 100 | \206\179 101 | \206\180 102 | \206\181 103 | \206\182 104 | \206\183 105 | \206\184 106 | \206\185 107 | \206\186 108 | \206\187 109 | \206\188 110 | \206\189 111 | \206\190 112 | \206\191 113 | \207\128 114 | \207\129 115 | \207\130 116 | \207\131 117 | \207\132 118 | \207\133 119 | \207\134 120 | \207\135 121 | \207\136 122 | \207\137 123 | \207\138 124 | \207\139 125 | \207\140 126 | \207\141 127 | \207\142 128 | 129 | -------------------------------------------------------------------------------- /lovefs-noffi/codepages/KOI8-R: -------------------------------------------------------------------------------- 1 | \226\148\128 2 | \226\148\130 3 | \226\148\140 4 | \226\148\144 5 | \226\148\148 6 | \226\148\152 7 | \226\148\156 8 | \226\148\164 9 | \226\148\172 10 | \226\148\180 11 | \226\148\188 12 | \226\150\128 13 | \226\150\132 14 | \226\150\136 15 | \226\150\140 16 | \226\150\144 17 | \226\150\145 18 | \226\150\146 19 | \226\150\147 20 | \226\140\160 21 | \226\150\160 22 | \226\136\153 23 | \226\136\154 24 | \226\137\136 25 | \226\137\164 26 | \226\137\165 27 | \194\160 28 | \226\140\161 29 | \194\176 30 | \194\178 31 | \194\183 32 | \195\183 33 | \226\149\144 34 | \226\149\145 35 | \226\149\146 36 | \209\145 37 | \226\149\147 38 | \226\149\148 39 | \226\149\149 40 | \226\149\150 41 | \226\149\151 42 | \226\149\152 43 | \226\149\153 44 | \226\149\154 45 | \226\149\155 46 | \226\149\156 47 | \226\149\157 48 | \226\149\158 49 | \226\149\159 50 | \226\149\160 51 | \226\149\161 52 | \208\129 53 | \226\149\162 54 | \226\149\163 55 | \226\149\164 56 | \226\149\165 57 | \226\149\166 58 | \226\149\167 59 | \226\149\168 60 | \226\149\169 61 | \226\149\170 62 | \226\149\171 63 | \226\149\172 64 | \194\169 65 | \209\142 66 | \208\176 67 | \208\177 68 | \209\134 69 | \208\180 70 | \208\181 71 | \209\132 72 | \208\179 73 | \209\133 74 | \208\184 75 | \208\185 76 | \208\186 77 | \208\187 78 | \208\188 79 | \208\189 80 | \208\190 81 | \208\191 82 | \209\143 83 | \209\128 84 | \209\129 85 | \209\130 86 | \209\131 87 | \208\182 88 | \208\178 89 | \209\140 90 | \209\139 91 | \208\183 92 | \209\136 93 | \209\141 94 | \209\137 95 | \209\135 96 | \209\138 97 | \208\174 98 | \208\144 99 | \208\145 100 | \208\166 101 | \208\148 102 | \208\149 103 | \208\164 104 | \208\147 105 | \208\165 106 | \208\152 107 | \208\153 108 | \208\154 109 | \208\155 110 | \208\156 111 | \208\157 112 | \208\158 113 | \208\159 114 | \208\175 115 | \208\160 116 | \208\161 117 | \208\162 118 | \208\163 119 | \208\150 120 | \208\146 121 | \208\172 122 | \208\171 123 | \208\151 124 | \208\168 125 | \208\173 126 | \208\169 127 | \208\167 128 | \208\170 129 | -------------------------------------------------------------------------------- /lovefs-noffi/codepages/KOI8-U: -------------------------------------------------------------------------------- 1 | \226\148\128 2 | \226\148\130 3 | \226\148\140 4 | \226\148\144 5 | \226\148\148 6 | \226\148\152 7 | \226\148\156 8 | \226\148\164 9 | \226\148\172 10 | \226\148\180 11 | \226\148\188 12 | \226\150\128 13 | \226\150\132 14 | \226\150\136 15 | \226\150\140 16 | \226\150\144 17 | \226\150\145 18 | \226\150\146 19 | \226\150\147 20 | \226\140\160 21 | \226\150\160 22 | \226\136\153 23 | \226\136\154 24 | \226\137\136 25 | \226\137\164 26 | \226\137\165 27 | \194\160 28 | \226\140\161 29 | \194\176 30 | \194\178 31 | \194\183 32 | \195\183 33 | \226\149\144 34 | \226\149\145 35 | \226\149\146 36 | \209\145 37 | \209\148 38 | \226\149\148 39 | \209\150 40 | \209\151 41 | \226\149\151 42 | \226\149\152 43 | \226\149\153 44 | \226\149\154 45 | \226\149\155 46 | \210\145 47 | \226\149\157 48 | \226\149\158 49 | \226\149\159 50 | \226\149\160 51 | \226\149\161 52 | \208\129 53 | \208\132 54 | \226\149\163 55 | \208\134 56 | \208\135 57 | \226\149\166 58 | \226\149\167 59 | \226\149\168 60 | \226\149\169 61 | \226\149\170 62 | \210\144 63 | \226\149\172 64 | \194\169 65 | \209\142 66 | \208\176 67 | \208\177 68 | \209\134 69 | \208\180 70 | \208\181 71 | \209\132 72 | \208\179 73 | \209\133 74 | \208\184 75 | \208\185 76 | \208\186 77 | \208\187 78 | \208\188 79 | \208\189 80 | \208\190 81 | \208\191 82 | \209\143 83 | \209\128 84 | \209\129 85 | \209\130 86 | \209\131 87 | \208\182 88 | \208\178 89 | \209\140 90 | \209\139 91 | \208\183 92 | \209\136 93 | \209\141 94 | \209\137 95 | \209\135 96 | \209\138 97 | \208\174 98 | \208\144 99 | \208\145 100 | \208\166 101 | \208\148 102 | \208\149 103 | \208\164 104 | \208\147 105 | \208\165 106 | \208\152 107 | \208\153 108 | \208\154 109 | \208\155 110 | \208\156 111 | \208\157 112 | \208\158 113 | \208\159 114 | \208\175 115 | \208\160 116 | \208\161 117 | \208\162 118 | \208\163 119 | \208\150 120 | \208\146 121 | \208\172 122 | \208\171 123 | \208\151 124 | \208\168 125 | \208\173 126 | \208\169 127 | \208\167 128 | \208\170 129 | -------------------------------------------------------------------------------- /lovefs-noffi/codepages/code.txt: -------------------------------------------------------------------------------- 1 | ─ 0x80 0x2500 0xE2, 0x94, 0x80 Box Drawings Light Horizontal 2 | │ 0x81 0x2502 0xE2, 0x94, 0x82 Box Drawings Light Vertical 3 | ┌ 0x82 0x250C 0xE2, 0x94, 0x8C Box Drawings Light Down And Right 4 | ┐ 0x83 0x2510 0xE2, 0x94, 0x90 Box Drawings Light Down And Left 5 | └ 0x84 0x2514 0xE2, 0x94, 0x94 Box Drawings Light Up And Right 6 | ┘ 0x85 0x2518 0xE2, 0x94, 0x98 Box Drawings Light Up And Left 7 | ├ 0x86 0x251C 0xE2, 0x94, 0x9C Box Drawings Light Vertical And Right 8 | ┤ 0x87 0x2524 0xE2, 0x94, 0xA4 Box Drawings Light Vertical And Left 9 | ┬ 0x88 0x252C 0xE2, 0x94, 0xAC Box Drawings Light Down And Horizontal 10 | ┴ 0x89 0x2534 0xE2, 0x94, 0xB4 Box Drawings Light Up And Horizontal 11 | ┼ 0x8A 0x253C 0xE2, 0x94, 0xBC Box Drawings Light Vertical And Horizontal 12 | ▀ 0x8B 0x2580 0xE2, 0x96, 0x80 Upper Half Block 13 | ▄ 0x8C 0x2584 0xE2, 0x96, 0x84 Lower Half Block 14 | █ 0x8D 0x2588 0xE2, 0x96, 0x88 Full Block 15 | ▌ 0x8E 0x258C 0xE2, 0x96, 0x8C Left Half Block 16 | ▐ 0x8F 0x2590 0xE2, 0x96, 0x90 Right Half Block 17 | ░ 0x90 0x2591 0xE2, 0x96, 0x91 Light Shade 18 | ▒ 0x91 0x2592 0xE2, 0x96, 0x92 Medium Shade 19 | ▓ 0x92 0x2593 0xE2, 0x96, 0x93 Dark Shade 20 | ⌠ 0x93 0x2320 0xE2, 0x8C, 0xA0 Top Half Integral 21 | ■ 0x94 0x25A0 0xE2, 0x96, 0xA0 Black Square 22 | ∙ 0x95 0x2219 0xE2, 0x88, 0x99 Bullet Operator 23 | √ 0x96 0x221A 0xE2, 0x88, 0x9A Square Root 24 | ≈ 0x97 0x2248 0xE2, 0x89, 0x88 Almost Equal To 25 | ≤ 0x98 0x2264 0xE2, 0x89, 0xA4 Less-than Or Equal To 26 | ≥ 0x99 0x2265 0xE2, 0x89, 0xA5 Greater-than Or Equal To 27 | 0x9A 0x00A0 0xC2, 0xA0 No-break Space 28 | ⌡ 0x9B 0x2321 0xE2, 0x8C, 0xA1 Bottom Half Integral 29 | ° 0x9C 0x00B0 0xC2, 0xB0 Degree Sign 30 | ² 0x9D 0x00B2 0xC2, 0xB2 Superscript Two 31 | · 0x9E 0x00B7 0xC2, 0xB7 Middle Dot 32 | ÷ 0x9F 0x00F7 0xC3, 0xB7 Division Sign 33 | ═ 0xA0 0x2550 0xE2, 0x95, 0x90 Box Drawings Double Horizontal 34 | ║ 0xA1 0x2551 0xE2, 0x95, 0x91 Box Drawings Double Vertical 35 | ╒ 0xA2 0x2552 0xE2, 0x95, 0x92 Box Drawings Down Single And Right Double 36 | ё 0xA3 0x0451 0xD1, 0x91 Cyrillic Small Letter Io 37 | є 0xA4 0x0454 0xD1, 0x94 Cyrillic Small Letter Ukrainian Ie 38 | ╔ 0xA5 0x2554 0xE2, 0x95, 0x94 Box Drawings Double Down And Right 39 | і 0xA6 0x0456 0xD1, 0x96 Cyrillic Small Letter Byelorussian-ukrainian I 40 | ї 0xA7 0x0457 0xD1, 0x97 Cyrillic Small Letter Yi (ukrainian) 41 | ╗ 0xA8 0x2557 0xE2, 0x95, 0x97 Box Drawings Double Down And Left 42 | ╘ 0xA9 0x2558 0xE2, 0x95, 0x98 Box Drawings Up Single And Right Double 43 | ╙ 0xAA 0x2559 0xE2, 0x95, 0x99 Box Drawings Up Double And Right Single 44 | ╚ 0xAB 0x255A 0xE2, 0x95, 0x9A Box Drawings Double Up And Right 45 | ╛ 0xAC 0x255B 0xE2, 0x95, 0x9B Box Drawings Up Single And Left Double 46 | ґ 0xAD 0x0491 0xD2, 0x91 Cyrillic Small Letter Ghe With Upturn 47 | ╝ 0xAE 0x255D 0xE2, 0x95, 0x9D Box Drawings Double Up And Left 48 | ╞ 0xAF 0x255E 0xE2, 0x95, 0x9E Box Drawings Vertical Single And Right Double 49 | ╟ 0xB0 0x255F 0xE2, 0x95, 0x9F Box Drawings Vertical Double And Right Single 50 | ╠ 0xB1 0x2560 0xE2, 0x95, 0xA0 Box Drawings Double Vertical And Right 51 | ╡ 0xB2 0x2561 0xE2, 0x95, 0xA1 Box Drawings Vertical Single And Left Double 52 | Ё 0xB3 0x0401 0xD0, 0x81 Cyrillic Capital Letter Io 53 | Є 0xB4 0x0404 0xD0, 0x84 Cyrillic Capital Letter Ukrainian Ie 54 | ╣ 0xB5 0x2563 0xE2, 0x95, 0xA3 Box Drawings Double Vertical And Left 55 | І 0xB6 0x0406 0xD0, 0x86 Cyrillic Capital Letter Byelorussian-ukrainian I 56 | Ї 0xB7 0x0407 0xD0, 0x87 Cyrillic Capital Letter Yi (ukrainian) 57 | ╦ 0xB8 0x2566 0xE2, 0x95, 0xA6 Box Drawings Double Down And Horizontal 58 | ╧ 0xB9 0x2567 0xE2, 0x95, 0xA7 Box Drawings Up Single And Horizontal Double 59 | ╨ 0xBA 0x2568 0xE2, 0x95, 0xA8 Box Drawings Up Double And Horizontal Single 60 | ╩ 0xBB 0x2569 0xE2, 0x95, 0xA9 Box Drawings Double Up And Horizontal 61 | ╪ 0xBC 0x256A 0xE2, 0x95, 0xAA Box Drawings Vertical Single And Horizontal Double 62 | Ґ 0xBD 0x0490 0xD2, 0x90 Cyrillic Capital Letter Ghe With Upturn 63 | ╬ 0xBE 0x256C 0xE2, 0x95, 0xAC Box Drawings Double Vertical And Horizontal 64 | © 0xBF 0x00A9 0xC2, 0xA9 Copyright Sign 65 | ю 0xC0 0x044E 0xD1, 0x8E Cyrillic Small Letter Yu 66 | а 0xC1 0x0430 0xD0, 0xB0 Cyrillic Small Letter A 67 | б 0xC2 0x0431 0xD0, 0xB1 Cyrillic Small Letter Be 68 | ц 0xC3 0x0446 0xD1, 0x86 Cyrillic Small Letter Tse 69 | д 0xC4 0x0434 0xD0, 0xB4 Cyrillic Small Letter De 70 | е 0xC5 0x0435 0xD0, 0xB5 Cyrillic Small Letter Ie 71 | ф 0xC6 0x0444 0xD1, 0x84 Cyrillic Small Letter Ef 72 | г 0xC7 0x0433 0xD0, 0xB3 Cyrillic Small Letter Ghe 73 | х 0xC8 0x0445 0xD1, 0x85 Cyrillic Small Letter Ha 74 | и 0xC9 0x0438 0xD0, 0xB8 Cyrillic Small Letter I 75 | й 0xCA 0x0439 0xD0, 0xB9 Cyrillic Small Letter Short I 76 | к 0xCB 0x043A 0xD0, 0xBA Cyrillic Small Letter Ka 77 | л 0xCC 0x043B 0xD0, 0xBB Cyrillic Small Letter El 78 | м 0xCD 0x043C 0xD0, 0xBC Cyrillic Small Letter Em 79 | н 0xCE 0x043D 0xD0, 0xBD Cyrillic Small Letter En 80 | о 0xCF 0x043E 0xD0, 0xBE Cyrillic Small Letter O 81 | п 0xD0 0x043F 0xD0, 0xBF Cyrillic Small Letter Pe 82 | я 0xD1 0x044F 0xD1, 0x8F Cyrillic Small Letter Ya 83 | р 0xD2 0x0440 0xD1, 0x80 Cyrillic Small Letter Er 84 | с 0xD3 0x0441 0xD1, 0x81 Cyrillic Small Letter Es 85 | т 0xD4 0x0442 0xD1, 0x82 Cyrillic Small Letter Te 86 | у 0xD5 0x0443 0xD1, 0x83 Cyrillic Small Letter U 87 | ж 0xD6 0x0436 0xD0, 0xB6 Cyrillic Small Letter Zhe 88 | в 0xD7 0x0432 0xD0, 0xB2 Cyrillic Small Letter Ve 89 | ь 0xD8 0x044C 0xD1, 0x8C Cyrillic Small Letter Soft Sign 90 | ы 0xD9 0x044B 0xD1, 0x8B Cyrillic Small Letter Yeru 91 | з 0xDA 0x0437 0xD0, 0xB7 Cyrillic Small Letter Ze 92 | ш 0xDB 0x0448 0xD1, 0x88 Cyrillic Small Letter Sha 93 | э 0xDC 0x044D 0xD1, 0x8D Cyrillic Small Letter E 94 | щ 0xDD 0x0449 0xD1, 0x89 Cyrillic Small Letter Shcha 95 | ч 0xDE 0x0447 0xD1, 0x87 Cyrillic Small Letter Che 96 | ъ 0xDF 0x044A 0xD1, 0x8A Cyrillic Small Letter Hard Sign 97 | Ю 0xE0 0x042E 0xD0, 0xAE Cyrillic Capital Letter Yu 98 | А 0xE1 0x0410 0xD0, 0x90 Cyrillic Capital Letter A 99 | Б 0xE2 0x0411 0xD0, 0x91 Cyrillic Capital Letter Be 100 | Ц 0xE3 0x0426 0xD0, 0xA6 Cyrillic Capital Letter Tse 101 | Д 0xE4 0x0414 0xD0, 0x94 Cyrillic Capital Letter De 102 | Е 0xE5 0x0415 0xD0, 0x95 Cyrillic Capital Letter Ie 103 | Ф 0xE6 0x0424 0xD0, 0xA4 Cyrillic Capital Letter Ef 104 | Г 0xE7 0x0413 0xD0, 0x93 Cyrillic Capital Letter Ghe 105 | Х 0xE8 0x0425 0xD0, 0xA5 Cyrillic Capital Letter Ha 106 | И 0xE9 0x0418 0xD0, 0x98 Cyrillic Capital Letter I 107 | Й 0xEA 0x0419 0xD0, 0x99 Cyrillic Capital Letter Short I 108 | К 0xEB 0x041A 0xD0, 0x9A Cyrillic Capital Letter Ka 109 | Л 0xEC 0x041B 0xD0, 0x9B Cyrillic Capital Letter El 110 | М 0xED 0x041C 0xD0, 0x9C Cyrillic Capital Letter Em 111 | Н 0xEE 0x041D 0xD0, 0x9D Cyrillic Capital Letter En 112 | О 0xEF 0x041E 0xD0, 0x9E Cyrillic Capital Letter O 113 | П 0xF0 0x041F 0xD0, 0x9F Cyrillic Capital Letter Pe 114 | Я 0xF1 0x042F 0xD0, 0xAF Cyrillic Capital Letter Ya 115 | Р 0xF2 0x0420 0xD0, 0xA0 Cyrillic Capital Letter Er 116 | С 0xF3 0x0421 0xD0, 0xA1 Cyrillic Capital Letter Es 117 | Т 0xF4 0x0422 0xD0, 0xA2 Cyrillic Capital Letter Te 118 | У 0xF5 0x0423 0xD0, 0xA3 Cyrillic Capital Letter U 119 | Ж 0xF6 0x0416 0xD0, 0x96 Cyrillic Capital Letter Zhe 120 | В 0xF7 0x0412 0xD0, 0x92 Cyrillic Capital Letter Ve 121 | Ь 0xF8 0x042C 0xD0, 0xAC Cyrillic Capital Letter Soft Sign 122 | Ы 0xF9 0x042B 0xD0, 0xAB Cyrillic Capital Letter Yeru 123 | З 0xFA 0x0417 0xD0, 0x97 Cyrillic Capital Letter Ze 124 | Ш 0xFB 0x0428 0xD0, 0xA8 Cyrillic Capital Letter Sha 125 | Э 0xFC 0x042D 0xD0, 0xAD Cyrillic Capital Letter E 126 | Щ 0xFD 0x0429 0xD0, 0xA9 Cyrillic Capital Letter Shcha 127 | Ч 0xFE 0x0427 0xD0, 0xA7 Cyrillic Capital Letter Che 128 | Ъ 0xFF 0x042A 0xD0, 0xAA Cyrillic Capital Letter Hard Sign 129 | -------------------------------------------------------------------------------- /lovefs-noffi/codepages/main.lua: -------------------------------------------------------------------------------- 1 | --f = io.open('KOI8-U.txt') 2 | for line in io.lines('code.txt') do 3 | for word in line:gmatch("0x%x+") do io.write('\\'..tonumber(word)..' ') end 4 | print() 5 | end 6 | -------------------------------------------------------------------------------- /lovefs-noffi/conf.lua: -------------------------------------------------------------------------------- 1 | function love.conf(t) 2 | t.title = "LoveFS" -- The title of the window the game is in (string) 3 | t.author = "linux-man" -- The author of the game (string) 4 | t.url = nil -- The website of the game (string) 5 | t.identity = nil -- The name of the save directory (string) 6 | t.version = "0.10.2" -- The LÖVE version this game was made for (string) 7 | t.console = false -- Attach a console (boolean, Windows only) 8 | t.window.width = 800 -- The window width (number) 9 | t.window.height = 600 -- The window height (number) 10 | t.window.fullscreen = false -- Enable fullscreen (boolean) 11 | t.window.vsync = true -- Enable vertical sync (boolean) 12 | t.window.fsaa = 0 -- The number of FSAA-buffers (number) 13 | t.modules.joystick = false -- Enable the joystick module (boolean) 14 | t.modules.audio = true -- Enable the audio module (boolean) 15 | t.modules.keyboard = true -- Enable the keyboard module (boolean) 16 | t.modules.event = true -- Enable the event module (boolean) 17 | t.modules.image = true -- Enable the image module (boolean) 18 | t.modules.graphics = true -- Enable the graphics module (boolean) 19 | t.modules.timer = true -- Enable the timer module (boolean) 20 | t.modules.mouse = true -- Enable the mouse module (boolean) 21 | t.modules.sound = true -- Enable the sound module (boolean) 22 | t.modules.physics = false -- Enable the physics module (boolean) 23 | end 24 | -------------------------------------------------------------------------------- /lovefs-noffi/dialogs.lua: -------------------------------------------------------------------------------- 1 | --[[------------------------------------ 2 | LoveFS Dialogs v0.8 3 | Pure Lua FileSystem Access - Loveframes interface 4 | Under the MIT license. 5 | copyright(c) 2012 Caldas Lopes aka linux-man 6 | --]]------------------------------------ 7 | 8 | require 'loveframes' 9 | 10 | local lovefs_dir = 'lovefs' 11 | 12 | local function normalize(str) 13 | local str2 = '' 14 | for n = 1, #str do 15 | if str:byte(n) < 128 then str2 = str2..str:sub(n, n) end 16 | end 17 | return str2 18 | end 19 | 20 | dialog = {} 21 | dialog.__index = dialog 22 | 23 | function dialog:refresh() 24 | self.current:SetText(self.window_fs.current) 25 | self.list:Clear() 26 | local i = loveframes.Create('button') 27 | i:SetSize(405, 25) 28 | i.image = up 29 | i:SetText('..') 30 | i.groupIndex = 1 31 | i.OnClick = function(object) 32 | self.window.selectedFile = '' 33 | self.window_fs:cd(object:GetText()) 34 | self:refresh() 35 | end 36 | self.list:AddItem(i) 37 | for _, d in ipairs(self.window_fs.dirs) do 38 | local i = loveframes.Create('button') 39 | i:SetSize(405, 25) 40 | i.image = folder 41 | i:SetText(d) 42 | i.groupIndex = 1 43 | i.OnClick = function(object) 44 | self.window.selectedFile = '' 45 | if self.fileinput then self.fileinput.text ='' end 46 | self.window_fs:cd(object:GetText()) 47 | self:refresh() 48 | end 49 | self.list:AddItem(i) 50 | end 51 | for _, f in ipairs(self.window_fs.files) do 52 | local i = loveframes.Create('button') 53 | i:SetSize(405, 25) 54 | i.image = file 55 | i:SetText(f) 56 | i.groupIndex = 1 57 | i.OnClick = function(object) 58 | if self.window_fs:isFile(object:GetText()) then 59 | self.window.selectedFile = object:GetText() 60 | if self.fileinput then self.fileinput.text = normalize(self.window.selectedFile) end 61 | end 62 | end 63 | self.list:AddItem(i) 64 | end 65 | end 66 | 67 | function dialog:default() 68 | folder = love.graphics.newImage(lovefs_dir..'/folder.png') 69 | file = love.graphics.newImage(lovefs_dir..'/file.png') 70 | up = love.graphics.newImage(lovefs_dir..'/up.png') 71 | 72 | self.window = loveframes.Create('frame') 73 | self.window:SetSize(415, 395) 74 | self.window:Center() 75 | self.window.selectedFile = '' 76 | --self.window:SetModal(true) --multichoice and tooltip don't play well with SetModal 77 | 78 | local drives = loveframes.Create('multichoice', self.window) 79 | local tooltip = loveframes.Create('tooltip') 80 | tooltip:SetObject(drives) 81 | tooltip:SetPadding(5) 82 | tooltip:SetOffsets(5, -5) 83 | tooltip:SetText('Drives') 84 | drives:SetPos(5, 25+5) 85 | drives:SetSize(100, 25) 86 | drives:SetListHeight(100) 87 | drives:SetPadding(0) 88 | drives:SetSpacing(0) 89 | drives.OnChoiceSelected = function(object, choice) 90 | self.window.selectedFile = '' 91 | self.window_fs:cd(choice) 92 | self:refresh() 93 | end 94 | local _, drive 95 | for _, drive in ipairs(self.window_fs.drives) do 96 | drives:AddChoice(drive) 97 | end 98 | drives:SetChoice(self.window_fs.drives[1]) 99 | 100 | self.current = loveframes.Create('button', self.window) 101 | local tooltip = loveframes.Create('tooltip') 102 | tooltip:SetObject(self.current) 103 | tooltip:SetPadding(5) 104 | tooltip:SetOffsets(5, -5) 105 | tooltip:SetText('Current Directory') 106 | self.current:SetPos(100+10, 25+5) 107 | self.current:SetSize(300, 25) 108 | self.current.image = folder 109 | self.current.checked = true 110 | self.current.enabled = false 111 | 112 | self.list = loveframes.Create('list', self.window) 113 | self.list:SetPos(5, 60) 114 | self.list:SetSize(405, 300) 115 | self.list:SetDisplayType('vertical') 116 | self.list:SetPadding(0) 117 | self.list:SetSpacing(0) 118 | 119 | local cancel = loveframes.Create('button', self.window) 120 | cancel:SetPos(410-75-80, 360+5) 121 | cancel:SetSize(75, 25) 122 | cancel:SetText('Cancel') 123 | cancel.OnClick = function(object) 124 | self.window:Remove() 125 | self = nil 126 | end 127 | local ok = loveframes.Create('button', self.window) 128 | ok:SetPos(410-75, 360+5) 129 | ok:SetSize(75, 25) 130 | ok:SetText('OK') 131 | ok.OnClick = function(object) 132 | if self.window.selectedFile ~= '' then 133 | if self.window_fs.os == 'Windows' then self.window_fs.selectedFile = self.window_fs.current..'\\'..self.window.selectedFile 134 | else self.window_fs.selectedFile = self.window_fs.current..'/'..self.window.selectedFile end 135 | self.window:Remove() 136 | self = nil 137 | end 138 | end 139 | end 140 | 141 | function loadDialog(window_fs, filters) 142 | local temp = {} 143 | setmetatable(temp, dialog) 144 | temp.window_fs = window_fs 145 | temp:default() 146 | local tb_filters = {} 147 | local _, v 148 | if filters then for _,v in ipairs(filters) do table.insert(tb_filters, v) end end 149 | temp.window:SetName('Load File') 150 | 151 | local filter = loveframes.Create('multichoice', temp.window) 152 | local tooltip = loveframes.Create('tooltip') 153 | tooltip:SetObject(filter) 154 | tooltip:SetPadding(5) 155 | tooltip:SetOffsets(5, -5) 156 | tooltip:SetText('Filter') 157 | filter:SetPos(5, 360+5) 158 | filter:SetSize(245, 25) 159 | filter:SetListHeight(100) 160 | filter:SetPadding(0) 161 | filter:SetSpacing(0) 162 | filter.OnChoiceSelected = function(object, choice) 163 | if choice:find('|') then window_fs:setParam(choice:sub(choice:find('|') + 1)) 164 | else window_fs:setParam(choice) end 165 | temp:refresh() 166 | end 167 | local _, f 168 | for _, f in ipairs(tb_filters) do 169 | filter:AddChoice(f) 170 | end 171 | filter:SetChoice(tb_filters[1]) 172 | if tb_filters[1]:find('|') then window_fs:setParam(tb_filters[1]:sub(tb_filters[1]:find('|') + 1)) 173 | else window_fs:setParam(tb_filters[1]) end 174 | temp:refresh() 175 | return temp 176 | end 177 | 178 | function saveDialog(window_fs) 179 | local temp = {} 180 | setmetatable(temp, dialog) 181 | temp.window_fs = window_fs 182 | temp:default() 183 | temp.window:SetName('Save File') 184 | 185 | temp.fileinput = loveframes.Create('textinput', temp.window) 186 | local tooltip = loveframes.Create('tooltip') 187 | tooltip:SetObject(temp.fileinput) 188 | tooltip:SetPadding(5) 189 | tooltip:SetOffsets(5, -5) 190 | tooltip:SetText('Filename') 191 | temp.fileinput:SetPos(5, 360+5) 192 | temp.fileinput:SetSize(245, 25) 193 | temp.fileinput.OnTextChanged = function(object, text) 194 | temp.window.selectedFile = object:GetText() 195 | end 196 | temp:refresh() 197 | return temp 198 | end 199 | -------------------------------------------------------------------------------- /lovefs-noffi/file.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linux-man/lovefs/e2aa001a657990b9c23807e917e6b9d869ac5a2e/lovefs-noffi/file.png -------------------------------------------------------------------------------- /lovefs-noffi/folder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linux-man/lovefs/e2aa001a657990b9c23807e917e6b9d869ac5a2e/lovefs-noffi/folder.png -------------------------------------------------------------------------------- /lovefs-noffi/lovefs.lua: -------------------------------------------------------------------------------- 1 | --[[------------------------------------ 2 | LoveFS v0.9 3 | Pure Lua FileSystem Access 4 | Under the MIT license. 5 | copyright(c) 2016 Caldas Lopes aka linux-man 6 | --]]------------------------------------ 7 | 8 | local lovefs_dir = 'lovefs' 9 | local cp_table = {'737', '775', '850', '852', '855', '866', '8859-1', '8859-2', '8859-4', '8859-5', '8859-7', '8859-15', '8859-16', 'KOI8-R', 'KOI8-U'} 10 | 11 | local function strformat(str) 12 | str = str:gsub('"', '') 13 | str = string.format('%q',str) 14 | while str:find('\\\\') do str = str:gsub('\\\\', '\\') end 15 | while str:find('//') do str = str:gsub('//', '/') end 16 | return str 17 | end 18 | 19 | local function split(str, sep) 20 | local sep, fields = sep or ":", {} 21 | local pattern = string.format("([^%s]+)", sep) 22 | str:gsub(pattern, function(c) fields[#fields+1] = c end) 23 | return fields 24 | end 25 | 26 | local function split_lines(str) 27 | local t = {} 28 | for line in str:gmatch("[^\r\n]+") do table.insert(t, line) end 29 | return t 30 | end 31 | 32 | local function join_tables(t1, t2) 33 | local tb = {} 34 | for _,v in ipairs(t1) do table.insert(tb, v) end 35 | for _,v in ipairs(t2) do table.insert(tb, v) end 36 | return tb 37 | end 38 | 39 | local function normalize_utf8(str, always) 40 | always = always or false 41 | local str2 = str 42 | local utfcodes = '194,195,196,197,198,200,203,206,207,208,209,210,226' 43 | if always or not pcall(function() love.graphics.print(str, 0, 0) end) then 44 | str2 = '' 45 | for n = 1, #str do 46 | if str:byte(n) < 128 then 47 | str2 = str2..str:sub(n, n) 48 | else 49 | if utfcodes:find(tostring(str:byte(n))) then str2 = str2..'?' end 50 | end 51 | end 52 | end 53 | return str2 54 | end 55 | 56 | local function normalize_cp(str) 57 | local str2 = '' 58 | for n = 1, #str do 59 | if str:byte(n) < 128 then str2 = str2..str:sub(n, n) 60 | else str2 = str2..'?' end 61 | end 62 | return str2 63 | end 64 | 65 | filesystem = {} 66 | filesystem.__index = filesystem 67 | 68 | function filesystem:loadCp(codepage) 69 | self.tb_utf8, self.tb_cp = nil, nil 70 | if not codepage then 71 | if self.os == 'Windows' then 72 | _, lang = self:run('chcp') 73 | lang = lang:gsub('\n', '') 74 | else 75 | _, lang = self:run('echo $LANG') 76 | lang = lang:gsub('\n', '') 77 | end 78 | codepage = lang 79 | for _, c in ipairs(cp_table) do 80 | if lang:find(c) then codepage = c end 81 | end 82 | end 83 | self.cp = codepage 84 | if not love.filesystem.isFile(lovefs_dir..'/codepages/'..codepage) then 85 | if self.current then self:cd(self.current) end 86 | return false 87 | end 88 | local count = 128 89 | self.tb_utf8, self.tb_cp = {}, {} 90 | for line in love.filesystem.lines(lovefs_dir..'/codepages/'..codepage) do 91 | if line ~= '' then 92 | self.tb_utf8[count] = split(line, '\\') 93 | self.tb_cp[line] = count 94 | end 95 | count = count + 1 96 | end 97 | if self.current then self:cd(self.current) end 98 | return true 99 | end 100 | 101 | function filesystem:toUtf8(str) 102 | if not self.tb_utf8 then return normalize_utf8(str) end 103 | local str2 = '' 104 | for n = 1, #str do 105 | if str:byte(n) < 128 then str2 = str2..str:sub(n, n) 106 | else 107 | if self.tb_utf8[str:byte(n)] then 108 | for _, n in ipairs(self.tb_utf8[str:byte(n)]) do 109 | str2 = str2..string.char(n) 110 | end 111 | else str2 = str2..str:sub(n, n) 112 | end 113 | end 114 | end 115 | return normalize_utf8(str2) 116 | end 117 | 118 | function filesystem:path8p3(dir, all) 119 | dir = dir or self.current 120 | if not (dir:sub(2,2) == ':') then dir = strformat(self.current..'\\'..dir):sub(2, -2) end 121 | dir = dir:gsub('/', '\\') 122 | local tb_dir = split(dir, '\\') 123 | local dir8p3 = tb_dir[1] 124 | table.remove(tb_dir, 1) 125 | while #tb_dir > 1 do 126 | local r, c = self:run('dir /X /AD '..strformat(dir8p3..'\\')) 127 | if not r then return self.current end 128 | local dir_result = split_lines(c) 129 | local name8p3 = '' 130 | for _, line in ipairs(dir_result) do 131 | if line:find('') and line:sub(50):find(tb_dir[1]:gsub("[%-]", "%%%0")) then 132 | if line:sub(37, 45):gsub(' ', '') ~= '' then 133 | name8p3 = line:sub(37, 45):gsub(' ', '') 134 | else 135 | name8p3 = line:sub(50) 136 | end 137 | end 138 | end 139 | if name8p3 ~= '' then dir8p3 = dir8p3..'\\'..name8p3 140 | else return self.current end 141 | table.remove(tb_dir, 1) 142 | end 143 | local name8p3 = tb_dir[1] 144 | if all then 145 | local r, c = self:run('dir /X /A-D '..strformat(dir8p3..'\\')) 146 | if not r then return self.current end 147 | local dir_result = split_lines(c) 148 | for _, line in ipairs(dir_result) do 149 | if line:sub(50):find(tb_dir[1]) then 150 | if line:sub(37, 45):gsub(' ', '') ~= '' then 151 | name8p3 = line:sub(37, 45):gsub(' ', '') 152 | else 153 | name8p3 = line:sub(50) 154 | end 155 | end 156 | end 157 | end 158 | return dir8p3..'\\'..name8p3 159 | end 160 | 161 | function filesystem:toCp(str) 162 | if not self.tb_cp then 163 | if self.os == 'Windows' then return normalize_utf8(str, true) 164 | else return str end 165 | end 166 | local str2 = '' 167 | for n = 1, #str do 168 | if str:byte(n) < 128 then str2 = str2..str:sub(n, n) 169 | else 170 | if n < #str-1 then 171 | if self.tb_cp['\\'..str:byte(n)..'\\'..str:byte(n+1)..'\\'..str:byte(n+2)] then 172 | str2 = str2..string.char(self.tb_cp['\\'..str:byte(n)..'\\'..str:byte(n+1)..'\\'..str:byte(n+2)]) 173 | n = n + 2 174 | elseif self.tb_cp['\\'..str:byte(n)..'\\'..str:byte(n+1)] then 175 | str2 = str2..string.char(self.tb_cp['\\'..str:byte(n)..'\\'..str:byte(n+1)]) 176 | n = n + 1 177 | end 178 | elseif n < #str then 179 | if self.tb_cp['\\'..str:byte(n)..'\\'..str:byte(n+1)] then 180 | str2 = str2..string.char(self.tb_cp['\\'..str:byte(n)..'\\'..str:byte(n+1)]) 181 | n = n + 1 182 | end 183 | end 184 | end 185 | end 186 | if self.os == 'Windows' then str2 = normalize_cp(str2) end 187 | return str2 188 | end 189 | 190 | function filesystem:run(command) 191 | if love._os == 'Windows' then 192 | console = self.tempdir..os.tmpname() 193 | else 194 | console = os.tmpname() 195 | end 196 | r = os.execute(self:toCp(command)..' > '.. console) 197 | c = '' 198 | for line in io.lines(console) do 199 | line = self:toUtf8(line) 200 | if c == '' then c = line 201 | else c = c..'\n'..line end 202 | end 203 | os.remove(console) 204 | return r, c 205 | end 206 | 207 | function filesystem:ls(param, dir) 208 | dir = dir or self.current 209 | param = param or '' 210 | if self.os == 'Windows' then 211 | local r, c = self:run('cd /D '..strformat(dir)..' & dir /B /A-S-H '..param) 212 | str = c 213 | else 214 | local r, c = self:run('cd '..strformat(dir)..' ; ls -1 '..param) 215 | str = c:gsub('/', '') 216 | end 217 | return split_lines(str), str 218 | end 219 | 220 | function filesystem:lsDirs(param, dir) 221 | dir = dir or self.current 222 | param = param or '' 223 | if self.os == 'Windows' then return self:ls('/A-S-HD /ON '..param, dir) 224 | else return self:ls('-p '..param..' | grep /\\$', dir) 225 | end 226 | end 227 | 228 | function filesystem:lsFiles(param, dir) 229 | dir = dir or self.current 230 | param = param or '' 231 | if self.os == 'Windows' then return self:ls('/A-S-H-D /ON '..param, dir) 232 | else return self:ls('-p '..param..' | grep -v /\\$', dir) 233 | end 234 | end 235 | 236 | function filesystem:exists(name, dir) 237 | dir = dir or self.current 238 | if self.os == 'Windows' then r, c = self:run('cd /D '..strformat(dir)..' & dir '..strformat(name)) 239 | else r, c = self:run('cd '..strformat(dir)..' ; ls '..strformat(name)) end 240 | return r == 0 241 | end 242 | 243 | function filesystem:isDirectory(name, dir) 244 | dir = dir or self.current 245 | if self.os == 'Windows' then r, c = self:run('cd /D '..strformat(dir)..' & cd '..strformat(name)) 246 | else r, c = self:run('cd '..strformat(dir)..' ; cd '..strformat(name)) end 247 | return r == 0 248 | end 249 | 250 | function filesystem:isFile(name, dir) 251 | return self:exists(name, dir) and not self:isDirectory(name, dir) 252 | end 253 | 254 | function filesystem:dir(param, dir) 255 | return self:ls(param, dir) 256 | end 257 | 258 | function filesystem:cd(dir) 259 | dir = dir or self.current 260 | if self.os == 'Windows' then 261 | if not (dir:sub(2,2) == ':') then dir = self.current..'\\'..dir end 262 | dir = strformat(dir) 263 | r, c = self:run('cd /D '..strformat(dir)) 264 | if r == 0 then 265 | r, c = self:run('cd /D '..strformat(dir)..' & cd') 266 | self.current = c:gsub('\n', '') 267 | self.dirs = self:lsDirs() 268 | self.files = self:lsFiles(self.param) 269 | self.all = join_tables(self.dirs, self.files) 270 | return true 271 | end 272 | else 273 | if not (dir:sub(1,1) == '/' or dir:sub(1,1) == '~') then dir = self.current..'/'..dir end 274 | dir = strformat(dir) 275 | r, c = self:run('cd '..dir) 276 | if r == 0 then 277 | r, c = self:run('cd '..dir..' ; pwd') 278 | self.current = c:gsub('//', '/'):gsub('\n', '') 279 | self.dirs = self:lsDirs() 280 | self.files = self:lsFiles(self.param) 281 | self.all = join_tables(self.dirs, self.files) 282 | return true 283 | end 284 | end 285 | return false 286 | end 287 | 288 | function filesystem:up() 289 | return self:cd('..') 290 | end 291 | 292 | function filesystem:setParam(param) 293 | if param then self.param = param end 294 | self:cd(self.current) 295 | end 296 | 297 | function filesystem:lsDrives() 298 | if self.os == 'Windows' then 299 | local str = io.popen('wmic logicaldisk get caption'):read('*all') 300 | if not str:find('C:') then str = 'default\nA:\nB:\nC:\nD:\nE:\nF:\nG:\nH:\nI:\nJ:\n' end 301 | tb = split_lines(self:toUtf8(str):gsub(' ', '')) 302 | table.remove(tb,1) 303 | elseif self.os == 'Linux' then 304 | tb = self:lsDirs('', '/media') 305 | for n, d in ipairs(tb) do tb[n] = '/media/'..tb[n] end 306 | table.insert(tb, 1, '/') 307 | else 308 | tb = self:lsDirs('', '/Volumes') 309 | for n, d in ipairs(tb) do tb[n] = '/Volumes/'..tb[n] end 310 | table.insert(tb, 1, '/') 311 | end 312 | return tb 313 | end 314 | 315 | function filesystem:copy(source, dest) 316 | love.filesystem.createDirectory('lovefs_temp') 317 | if self.os == 'Windows' then 318 | source = strformat(self:path8p3(self:toCp(source), true)):sub(2, -2) 319 | dest = strformat(self:path8p3(self:toCp(dest))):sub(2, -2) 320 | else 321 | source = strformat(self:toCp(source)):sub(2, -2) 322 | dest = strformat(self:toCp(dest)):sub(2, -2) 323 | end 324 | local inp = assert(io.open(source, "rb")) 325 | local out = assert(io.open(dest, "wb")) 326 | local data = inp:read("*all") 327 | out:write(data) 328 | assert(out:close()) 329 | end 330 | 331 | function filesystem:loadImage(source) 332 | source = source or self.selectedFile 333 | self.selectedFile = nil 334 | love.filesystem.createDirectory('lovefs_temp') 335 | self:copy(source, love.filesystem.getSaveDirectory()..'/lovefs_temp/temp.file') 336 | return love.graphics.newImage('lovefs_temp/temp.file') 337 | end 338 | 339 | function filesystem:loadSource(source) 340 | source = source or self.selectedFile 341 | self.selectedFile = nil 342 | love.filesystem.createDirectory('lovefs_temp') 343 | self:copy(source, love.filesystem.getSaveDirectory()..'/lovefs_temp/temp.'..source:sub(-3)) 344 | return love.audio.newSource('lovefs_temp/temp.'..source:sub(-3)) 345 | end 346 | 347 | function filesystem:loadFont(size, source) 348 | source = source or self.selectedFile 349 | self.selectedFile = nil 350 | love.filesystem.createDirectory('lovefs_temp') 351 | self:copy(source, love.filesystem.getSaveDirectory()..'/lovefs_temp/temp.file') 352 | return love.graphics.newFont('lovefs_temp/temp.file', size) 353 | end 354 | 355 | function filesystem:saveImage(img, dest) 356 | if not pcall(function() love.graphics.newCanvas(img:getWidth(), img:getHeight()) end) then return false end 357 | dest = dest or self.selectedFile 358 | self.selectedFile = nil 359 | love.filesystem.createDirectory('lovefs_temp') 360 | love.graphics.setColor(255, 255, 255) 361 | local canvas = love.graphics.newCanvas(img:getWidth(), img:getHeight()) 362 | love.graphics.setCanvas(canvas) 363 | love.graphics.draw(img, 0, 0) 364 | local id = canvas:getImageData() 365 | local tb = split(dest, '.') 366 | id:encode('lovefs_temp/temp.'..tb[#tb]) 367 | self:copy(love.filesystem.getSaveDirectory()..'/lovefs_temp/temp.'..tb[#tb], dest) 368 | return true 369 | end 370 | 371 | function lovefs(dir) 372 | local temp = {} 373 | setmetatable(temp, filesystem) 374 | temp.os = love.system.getOS() 375 | temp.param = '' 376 | temp.selectedFile = nil 377 | if temp.os == 'Windows' then 378 | temp.tempdir = io.popen('echo %TEMP%'):read('*all'):gsub('\n', '') 379 | else 380 | temp.tempdir = '' 381 | end 382 | temp.home = love.filesystem.getUserDirectory() 383 | temp.current = temp.home 384 | dir = dir or temp.home 385 | temp:loadCp() 386 | if not temp:cd(dir) then 387 | if not temp:cd(temp.home) then 388 | if temp.os == 'Windows' then temp:cd('c:\\') 389 | else temp:cd('/') end 390 | end 391 | end 392 | temp.drives = temp:lsDrives() 393 | return temp 394 | end 395 | -------------------------------------------------------------------------------- /lovefs-noffi/main.lua: -------------------------------------------------------------------------------- 1 | loveframes = require("loveframes") 2 | require 'lovefs/lovefs' 3 | require 'lovefs/dialogs' 4 | 5 | function love.load() 6 | fsload = lovefs() 7 | fssave = lovefs() 8 | fslsnd = lovefs() 9 | fslttf = lovefs() 10 | 11 | btload = loveframes.Create('button', window) 12 | btload:SetPos(0,5) 13 | btload:SetSize(200, 25) 14 | btload:SetText('Load Image') 15 | btload.OnClick = function(object) 16 | l = loadDialog(fsload, {'All | *.*', 'Jpeg | *.jpg *.jpeg', 'PNG | *.png', 'Bitmap | *.bmp', '*.gif'}) 17 | end 18 | 19 | btsave = loveframes.Create('button', window) 20 | btsave:SetPos(200,5) 21 | btsave:SetSize(200, 25) 22 | btsave:SetText('Save Image') 23 | btsave.OnClick = function(object) 24 | if img then s = saveDialog(fssave) end 25 | end 26 | 27 | btlsnd = loveframes.Create('button', window) 28 | btlsnd:SetPos(400,5) 29 | btlsnd:SetSize(200, 25) 30 | btlsnd:SetText('Load Sound') 31 | btlsnd.OnClick = function(object) 32 | s = loadDialog(fslsnd, {'All | *.*', 'Sound | *.mp3 *.wav'}) 33 | end 34 | 35 | btlttf = loveframes.Create('button', window) 36 | btlttf:SetPos(600,5) 37 | btlttf:SetSize(200, 25) 38 | btlttf:SetText('Load TrueType') 39 | btlttf.OnClick = function(object) 40 | t = loadDialog(fslttf, {'All | *.*', 'TrueType | *.ttf'}) 41 | end 42 | end 43 | 44 | function love.update(dt) 45 | if fsload.selectedFile then 46 | img = fsload:loadImage() 47 | end 48 | if fssave and fssave.selectedFile then 49 | fssave:saveImage(img) 50 | end 51 | if fslsnd.selectedFile then 52 | sound = fslsnd:loadSource() 53 | sound:play() 54 | end 55 | if fslttf.selectedFile then 56 | font = fslttf:loadFont(32) 57 | end 58 | loveframes.update(dt) 59 | end 60 | 61 | function love.draw() 62 | love.graphics.setColor(255, 255, 255) 63 | if img then 64 | love.graphics.draw(img, 0, 0, 0, math.min(800 / img:getWidth(), 600 / img:getHeight()), math.min(800 / img:getWidth(), 600 / img:getHeight())) 65 | end 66 | if font then love.graphics.setFont(font) end 67 | love.graphics.print('LoveFS Demo', 5, 550) 68 | loveframes.draw() 69 | end 70 | 71 | function love.mousepressed(x, y, button) 72 | loveframes.mousepressed(x, y, button) 73 | end 74 | 75 | function love.mousereleased(x, y, button) 76 | loveframes.mousereleased(x, y, button) 77 | end 78 | 79 | function love.keypressed(key, unicode) 80 | loveframes.keypressed(key, unicode) 81 | end 82 | 83 | function love.keyreleased(key, unicode) 84 | loveframes.keyreleased(key) 85 | end 86 | 87 | function love.textinput(text) 88 | loveframes.textinput(text) 89 | end 90 | -------------------------------------------------------------------------------- /lovefs-noffi/up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linux-man/lovefs/e2aa001a657990b9c23807e917e6b9d869ac5a2e/lovefs-noffi/up.png -------------------------------------------------------------------------------- /lovefs/gspotDialog.lua: -------------------------------------------------------------------------------- 1 | --[[------------------------------------ 2 | LoveFS Gspot Dialogs v1.2 3 | Pure Lua FileSystem Access - Loveframes interface 4 | Under the MIT license. 5 | copyright(c) 2016 Caldas Lopes aka linux-man 6 | --]]------------------------------------ 7 | 8 | local path = string.sub(..., 1, string.len(...) - string.len('gspotDialog'))..'images/' 9 | local folderImg = love.graphics.newImage(path..'folder.png') 10 | local fileImg = love.graphics.newImage(path..'file.png') 11 | local upImg = love.graphics.newImage(path..'up.png') 12 | local dScrollGroup 13 | local dDir 14 | local dFilename 15 | local dOK 16 | local drives 17 | local filter 18 | 19 | local function closeColGroup(colGroup) 20 | if colGroup then 21 | for _, opt in ipairs(colGroup.children) do 22 | if not (opt.label == '=' or opt.label == '-') then opt:hide() end 23 | end 24 | colGroup.view = false 25 | colGroup.control.label = '=' 26 | end 27 | end 28 | 29 | local function closeDialog(self) 30 | self.filter = nil 31 | self.dialog.Gspot:rem(self.dialog) 32 | self.dialog = nil 33 | dScrollGroup = nil 34 | dDir = nil 35 | dFilename = nil 36 | dOK = nil 37 | drives = nil 38 | filter = nil 39 | end 40 | 41 | local function updDialog(self) 42 | local gspot = self.dialog.Gspot 43 | if dScrollGroup then gspot:rem(dScrollGroup) end 44 | if drives then gspot:rem(drives) end 45 | dScrollGroup = gspot:scrollgroup(nil, {0, gspot.style.unit * 2, self.dialog.pos.w - gspot.style.unit, self.dialog.pos.h - gspot.style.unit * 4}, self.dialog, 'vertical') 46 | 47 | drives = gspot:collapsegroup('Change Drive', {0, gspot.style.unit, gspot.style.unit * 8, gspot.style.unit}, self.dialog) 48 | drives.tip = 'Drives' 49 | for i, drive in ipairs(self.drives) do 50 | local option = gspot:option(drive, {0, gspot.style.unit * i, drives.pos.w, gspot.style.unit}, drives, i) 51 | option:hide() 52 | option.click = function(this) 53 | this.parent:toggle() 54 | this.parent.label = this.label 55 | this.parent.value = this.value 56 | self:cd(this.label) 57 | updDialog(self) 58 | end 59 | end 60 | drives.view = false 61 | drives.control.label = '=' 62 | drives.control.click = function(this) this.parent:toggle() end 63 | 64 | local hid = gspot:hidden('', {0, 0, self.dialog.pos.w - gspot.style.unit, gspot.style.unit}, nil) 65 | local img = gspot:image('', {0, 0, gspot.style.unit, gspot.style.unit}, hid, upImg) 66 | local btn = gspot:text('..', {gspot.style.unit, 0, self.dialog.pos.w - gspot.style.unit * 2, gspot.style.unit}, hid) 67 | btn.style.fg = {200, 200, 200, 255} 68 | btn.enter = function(this) 69 | btn.style.fg = {255, 255, 255, 255} 70 | closeColGroup(drives) 71 | closeColGroup(filter) 72 | end 73 | btn.leave = function(this) 74 | btn.style.fg = {200, 200, 200, 255} 75 | end 76 | btn.click = function(this) 77 | self:up() 78 | updDialog(self) 79 | end 80 | dScrollGroup:addchild(hid, 'vertical') 81 | 82 | for _, v in ipairs(self.dirs) do 83 | local hid = gspot:hidden('', {0, 0, self.dialog.pos.w - gspot.style.unit, gspot.style.unit}, nil) 84 | local img = gspot:image('', {0, 0, gspot.style.unit, gspot.style.unit}, hid, folderImg) 85 | local btn = gspot:text(v, {gspot.style.unit, 0, self.dialog.pos.w - gspot.style.unit * 2, gspot.style.unit}, hid) 86 | btn.style.fg = {200, 200, 200, 255} 87 | btn.enter = function(this) 88 | btn.style.fg = {255, 255, 255, 255} 89 | closeColGroup(drives) 90 | closeColGroup(filter) 91 | end 92 | btn.leave = function(this) 93 | btn.style.fg = {200, 200, 200, 255} 94 | end 95 | btn.click = function(this) 96 | if self:isDirectory(btn.label) then self:cd(btn.label) end 97 | updDialog(self) 98 | end 99 | dScrollGroup:addchild(hid, 'vertical') 100 | end 101 | for _, v in ipairs(self.files) do 102 | local hid = gspot:hidden('', {0, 0, self.dialog.pos.w - gspot.style.unit, gspot.style.unit}, nil) 103 | local img = gspot:image('', {0, 0, gspot.style.unit, gspot.style.unit}, hid, fileImg) 104 | local btn = gspot:text(v, {gspot.style.unit, 0, self.dialog.pos.w - gspot.style.unit * 2, gspot.style.unit}, hid) 105 | btn.style.fg = {200, 200, 200, 255} 106 | btn.enter = function(this) 107 | btn.style.fg = {255, 255, 255, 255} 108 | closeColGroup(drives) 109 | closeColGroup(filter) 110 | end 111 | btn.leave = function(this) 112 | btn.style.fg = {200, 200, 200, 255} 113 | end 114 | btn.click = function(this) 115 | if self:isFile(btn.label) then dFilename.value = btn.label end 116 | end 117 | dScrollGroup:addchild(hid, 'vertical') 118 | end 119 | dDir.label = self.current 120 | dFilename.value = '' 121 | end 122 | 123 | local function init(self, gspot, label) 124 | self:cd() 125 | self.dialog = gspot:group(label, {love.graphics.getWidth( )/2 - 200, love.graphics.getHeight()/2 - 200, 400, 400}) 126 | self.dialog.drag = true 127 | 128 | dDir = gspot:text(self.current, {gspot.style.unit * 8, gspot.style.unit, self.dialog.pos.w - gspot.style.unit * 8, gspot.style.unit}, self.dialog) 129 | dDir.tip = 'Current Directory' 130 | 131 | dOk = gspot:button('OK', {self.dialog.pos.w - gspot.style.unit * 4, self.dialog.pos.h - gspot.style.unit, gspot.style.unit * 4, gspot.style.unit}, self.dialog) 132 | dOk.click = function(this, x, y, button) 133 | if not (dFilename.value == '') then 134 | self.selectedFile = self:absPath(dFilename.value) 135 | closeDialog(self) 136 | end 137 | end 138 | 139 | local button = gspot:button('X', {self.dialog.pos.w - gspot.style.unit, 0}, self.dialog) 140 | button.click = function(this) 141 | closeDialog(self) 142 | end 143 | local button = gspot:button('up', {self.dialog.pos.w - gspot.style.unit, gspot.style.unit}, self.dialog) 144 | button.click = function(this) 145 | local scroll = dScrollGroup.scrollv 146 | scroll.values.current = math.max(scroll.values.min, scroll.values.current - scroll.values.step) 147 | end 148 | local button = gspot:button('dn', {self.dialog.pos.w - gspot.style.unit, self.dialog.pos.h - gspot.style.unit * 2}, self.dialog) 149 | button.click = function(this) 150 | local scroll = dScrollGroup.scrollv 151 | scroll.values.current = math.min(scroll.values.max, scroll.values.current + scroll.values.step) 152 | end 153 | end 154 | 155 | function filesystem:loadDialog(gspot, label, filters) 156 | if self.dialog then 157 | closeDialog(self) 158 | end 159 | label = label or 'Load File' 160 | init(self, gspot, label) 161 | 162 | filter = gspot:collapsegroup('*.*', {0, self.dialog.pos.h - gspot.style.unit, gspot.style.unit * 8, gspot.style.unit}, self.dialog) 163 | filter.tip = 'Filters' 164 | if filters and type(filters) == "table" then 165 | for i, f in ipairs(filters) do 166 | local option = gspot:option(f, {0, gspot.style.unit * i, filter.pos.w, gspot.style.unit}, filter, i) 167 | option:hide() 168 | option.click = function(this) 169 | this.parent:toggle() 170 | this.parent.label = this.label 171 | this.parent.value = this.value 172 | self:setFilter(this.label) 173 | updDialog(self) 174 | end 175 | end 176 | filter.label = filters[1] 177 | self:setFilter(filters[1]) 178 | else 179 | self:setFilter(nil) 180 | end 181 | filter.view = false 182 | filter.control.label = '=' 183 | filter.control.click = function(this) this.parent:toggle() end 184 | 185 | dFilename = gspot:input(nil, {gspot.style.unit * 8, self.dialog.pos.h - gspot.style.unit, self.dialog.pos.w - gspot.style.unit * 12, gspot.style.unit}, self.dialog) 186 | 187 | dFilename.textinput = function(this, key) end 188 | dFilename.keypress = function(this, key) end 189 | 190 | updDialog(self) 191 | end 192 | 193 | function filesystem:saveDialog(gspot, label) 194 | if self.dialog then 195 | closeDialog(self) 196 | end 197 | label = label or 'Save File' 198 | self.filter = nil 199 | init(self, gspot, label) 200 | 201 | dFilename = gspot:input('Filename', {gspot.style.unit * 4, self.dialog.pos.h - gspot.style.unit, self.dialog.pos.w - gspot.style.unit * 8, gspot.style.unit}, self.dialog) 202 | 203 | dFilename.done = function(this) 204 | if not (this.value == '') then 205 | self.selectedFile = self:absPath(this.value) 206 | closeDialog(self) 207 | end 208 | end 209 | 210 | updDialog(self) 211 | end 212 | -------------------------------------------------------------------------------- /lovefs/images/file.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linux-man/lovefs/e2aa001a657990b9c23807e917e6b9d869ac5a2e/lovefs/images/file.png -------------------------------------------------------------------------------- /lovefs/images/folder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linux-man/lovefs/e2aa001a657990b9c23807e917e6b9d869ac5a2e/lovefs/images/folder.png -------------------------------------------------------------------------------- /lovefs/images/up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linux-man/lovefs/e2aa001a657990b9c23807e917e6b9d869ac5a2e/lovefs/images/up.png -------------------------------------------------------------------------------- /lovefs/loveframesDialog.lua: -------------------------------------------------------------------------------- 1 | --[[------------------------------------ 2 | LoveFS LoveFrames Dialogs v1.1 3 | Pure Lua FileSystem Access - Loveframes interface 4 | Under the MIT license. 5 | copyright(c) 2016 Caldas Lopes aka linux-man 6 | --]]------------------------------------ 7 | 8 | local path = string.sub(..., 1, string.len(...) - string.len('loveframesDialog'))..'images/' 9 | local folderImg = love.graphics.newImage(path..'folder.png') 10 | local fileImg = love.graphics.newImage(path..'file.png') 11 | local upImg = love.graphics.newImage(path..'up.png') 12 | local dDir 13 | local list 14 | local fileinput 15 | 16 | local function updDialog(self, lf) 17 | dDir:SetText(self.current) 18 | list:Clear() 19 | local i = lf.Create('button') 20 | i:SetSize(405, 25) 21 | i.image = upImg 22 | i:SetText('..') 23 | i.groupIndex = 1 24 | i.OnClick = function(object) 25 | self.dialog.selectedFile = nil 26 | self:up() 27 | updDialog(self, lf) 28 | end 29 | list:AddItem(i) 30 | for _, d in ipairs(self.dirs) do 31 | local i = lf.Create('button') 32 | i:SetSize(405, 25) 33 | i.image = folderImg 34 | i:SetText(d) 35 | i.groupIndex = 1 36 | i.OnClick = function(object) 37 | self.dialog.selectedFile = nil 38 | if fileinput then fileinput.text ='' end 39 | self:cd(object:GetText()) 40 | updDialog(self, lf) 41 | end 42 | list:AddItem(i) 43 | end 44 | for _, f in ipairs(self.files) do 45 | local i = lf.Create('button') 46 | i:SetSize(405, 25) 47 | i.image = fileImg 48 | i:SetText(f) 49 | i.groupIndex = 1 50 | i.OnClick = function(object) 51 | if self:isFile(object:GetText()) then 52 | self.dialog.selectedFile = object:GetText() 53 | if fileinput then fileinput:SetText(object:GetText()) end 54 | end 55 | end 56 | list:AddItem(i) 57 | end 58 | end 59 | 60 | local function closeDialog(self) 61 | self.dialog:Remove() 62 | self.dialog = nil 63 | dDir = nil 64 | list = nil 65 | fileinput = nil 66 | self.filter = nil 67 | end 68 | 69 | local function init(self, lf, label) 70 | self.dialog = lf.Create('frame') 71 | self.dialog:SetName('Load File') 72 | self.dialog:SetSize(415, 395) 73 | self.dialog:Center() 74 | self.dialog:SetModal(true) 75 | self.dialog.OnClose = function(object) 76 | closeDialog(self) 77 | end 78 | 79 | local drives = lf.Create('multichoice', self.dialog) 80 | local tooltip = lf.Create('tooltip') 81 | tooltip:SetObject(drives) 82 | tooltip:SetPadding(5) 83 | tooltip:SetOffsets(5, -5) 84 | tooltip:SetText('Drives') 85 | drives:SetPos(5, 25+5) 86 | drives:SetSize(100, 25) 87 | drives:SetListHeight(100) 88 | drives:SetPadding(0) 89 | drives:SetSpacing(0) 90 | drives.OnChoiceSelected = function(object, choice) 91 | self.dialog.selectedFile = nil 92 | self:cd(choice) 93 | updDialog(self, lf) 94 | end 95 | 96 | for _, drive in ipairs(self.drives) do 97 | drives:AddChoice(drive) 98 | end 99 | drives.text = 'Change Drive' 100 | 101 | dDir = lf.Create('button', self.dialog) 102 | local tooltip = lf.Create('tooltip') 103 | tooltip:SetObject(dDir) 104 | tooltip:SetPadding(5) 105 | tooltip:SetOffsets(5, -5) 106 | tooltip:SetText('Current Directory') 107 | dDir:SetPos(100+10, 25+5) 108 | dDir:SetSize(300, 25) 109 | dDir.image = folderImg 110 | dDir.checked = true 111 | dDir.enabled = false 112 | 113 | list = lf.Create('list', self.dialog) 114 | list:SetPos(5, 60) 115 | list:SetSize(405, 300) 116 | list:SetDisplayType('vertical') 117 | list:SetPadding(0) 118 | list:SetSpacing(0) 119 | 120 | local cancel = lf.Create('button', self.dialog) 121 | cancel:SetPos(410-75-80, 360+5) 122 | cancel:SetSize(75, 25) 123 | cancel:SetText('Cancel') 124 | cancel.OnClick = function(object) 125 | closeDialog(self) 126 | end 127 | local ok = lf.Create('button', self.dialog) 128 | ok:SetPos(410-75, 360+5) 129 | ok:SetSize(75, 25) 130 | ok:SetText('OK') 131 | ok.OnClick = function(object) 132 | if self.dialog.selectedFile then 133 | self.selectedFile = self.dialog.selectedFile 134 | closeDialog(self) 135 | end 136 | end 137 | end 138 | 139 | function filesystem:loadDialog(lf, label, filters) 140 | label = label or 'Load File' 141 | self:cd() 142 | init(self, lf, label) 143 | 144 | local filter = lf.Create('multichoice', self.dialog) 145 | local tooltip = lf.Create('tooltip') 146 | tooltip:SetObject(filter) 147 | tooltip:SetPadding(5) 148 | tooltip:SetOffsets(5, -5) 149 | tooltip:SetText('Filter') 150 | filter:SetPos(5, 360+5) 151 | filter:SetSize(245, 25) 152 | filter:SetListHeight(100) 153 | filter:SetPadding(0) 154 | filter:SetSpacing(0) 155 | filter.OnChoiceSelected = function(object, choice) 156 | self:setFilter(choice) 157 | updDialog(self, lf) 158 | end 159 | if filters and type(filters) == "table" then 160 | for _, f in ipairs(filters) do filter:AddChoice(f) end 161 | filter:SetChoice(filters[1]) 162 | self:setFilter(filters[1]) 163 | else 164 | filter:SetChoice('*.*') 165 | self:setFilter(nil) 166 | end 167 | 168 | updDialog(self, lf) 169 | end 170 | 171 | function filesystem:saveDialog(lf, label) 172 | self.filter = nil 173 | label = label or 'Save File' 174 | self:cd() 175 | init(self, lf, label) 176 | 177 | fileinput = lf.Create('textinput', self.dialog) 178 | local tooltip = lf.Create('tooltip') 179 | tooltip:SetObject(fileinput) 180 | tooltip:SetPadding(5) 181 | tooltip:SetOffsets(5, -5) 182 | tooltip:SetText('Filename') 183 | fileinput:SetPos(5, 360+5) 184 | fileinput:SetSize(245, 25) 185 | fileinput.OnTextChanged = function(object, text) 186 | self.dialog.selectedFile = object:GetText() 187 | end 188 | updDialog(self, lf) 189 | end 190 | -------------------------------------------------------------------------------- /lovefs/lovefs.lua: -------------------------------------------------------------------------------- 1 | --[[------------------------------------ 2 | LoveFS v2.0 3 | Pure Lua FileSystem Access 4 | Under the MIT license. 5 | copyright(c) 2025 Caldas Lopes aka linux-man 6 | --]]------------------------------------ 7 | 8 | local ffi = require("ffi") 9 | 10 | local osx = ffi.os == "OSX" or nil 11 | local linux = ffi.os == "Linux" or nil 12 | local win = ffi.os =="Windows" or nil 13 | 14 | local function findValue(tb, value) 15 | for _, v in ipairs(tb) do 16 | if v == value then return true end 17 | end 18 | return false 19 | end 20 | 21 | filesystem = {} 22 | filesystem.__index = filesystem 23 | 24 | local path = (...):match(".+/") 25 | if win then require (path .. "lovefs_win") 26 | elseif osx then require (path .. "lovefs_osx") 27 | elseif linux then require (path .. "lovefs_linux") 28 | else error('Platform not supported') end 29 | 30 | function filesystem:switchHidden() 31 | self.showHidden = not self.showHidden 32 | self:cd() 33 | end 34 | 35 | function filesystem:setFilter(filter) 36 | self.filter = nil 37 | if type(filter) == "table" then 38 | self.filter = filter 39 | elseif type(filter) == "string" then 40 | local t = {} 41 | f = filter:sub((filter:find('|') or 0) + 1) 42 | for i in string.gmatch(f, "%S+") do 43 | i = i:gsub('[%*%.%;]', '') 44 | if i ~= '' then table.insert(t, i) end 45 | end 46 | if #t > 0 then self.filter = t end 47 | end 48 | self:cd() 49 | end 50 | 51 | function filesystem:dir(dir) 52 | return self:ls(dir) 53 | end 54 | 55 | function filesystem:cd(dir) 56 | current, tDirs, tFiles, tOthers, tAll = self:ls(dir) 57 | if current then 58 | self.current = current 59 | self.dirs = tDirs 60 | self.files = tFiles 61 | self.others = tOthers 62 | self.all = tAll 63 | return true 64 | end 65 | return false 66 | end 67 | 68 | function filesystem:up() 69 | self:cd(self.current:match('(.*'..self.sep..')')) 70 | end 71 | 72 | function filesystem:exists(path) 73 | path = self:absPath(path) 74 | dir = self:absPath(path:match('(.*'..self.sep..')')) 75 | name = path:match('[^'..self.sep..']+$') 76 | --ext = name:match('[^.]+$') 77 | dir, dirs, files, others, all = self:ls(dir) 78 | if dir then 79 | return findValue(all, name), findValue(dirs, name), findValue(files, name) 80 | end 81 | return false 82 | end 83 | 84 | function filesystem:isDirectory(path) 85 | exists, isDir = self:exists(path) 86 | if exists then return isDir 87 | else return false end 88 | end 89 | 90 | function filesystem:isFile(path) 91 | exists, isDir, isFile = self:exists(path) 92 | if exists then return isFile 93 | else return false end 94 | end 95 | 96 | function filesystem:loadImage(source) 97 | source = source or self.selectedFile 98 | self.selectedFile = nil 99 | source = self:absPath(source) 100 | love.filesystem.createDirectory('lovefs_temp') 101 | self:copy(source, love.filesystem.getSaveDirectory()..'/lovefs_temp/temp.file') 102 | return love.graphics.newImage('lovefs_temp/temp.file') 103 | end 104 | 105 | function filesystem:loadSource(source) 106 | source = source or self.selectedFile 107 | self.selectedFile = nil 108 | source = self:absPath(source) 109 | love.filesystem.createDirectory('lovefs_temp') 110 | --local name = path:match('[^'..self.sep..']+$') 111 | local ext = source:match('[^'..self.sep..']+$'):match('[^.]+$') 112 | self:copy(source, love.filesystem.getSaveDirectory()..'/lovefs_temp/temp.'..ext) 113 | return love.audio.newSource('lovefs_temp/temp.'..ext, 'static') 114 | end 115 | 116 | function filesystem:loadFont(size, source) 117 | source = source or self.selectedFile 118 | self.selectedFile = nil 119 | source = self:absPath(source) 120 | love.filesystem.createDirectory('lovefs_temp') 121 | self:copy(source, love.filesystem.getSaveDirectory()..'/lovefs_temp/temp.file') 122 | return love.graphics.newFont('lovefs_temp/temp.file', size) 123 | end 124 | 125 | function filesystem:saveImage(img, dest) 126 | if not pcall(function() love.graphics.newCanvas(img:getWidth(), img:getHeight()) end) then return false end 127 | dest = dest or self.selectedFile 128 | dest = self:absPath(dest) 129 | self.selectedFile = nil 130 | love.filesystem.createDirectory('lovefs_temp') 131 | love.filesystem.remove('lovefs_temp/temp.file') 132 | love.graphics.setColor(255, 255, 255) 133 | local canvas = love.graphics.newCanvas(img:getWidth(), img:getHeight()) 134 | love.graphics.setCanvas(canvas) 135 | love.graphics.draw(img, 0, 0) 136 | love.graphics.setCanvas() 137 | local id = canvas:newImageData() 138 | id:encode('png', 'lovefs_temp/temp.file') 139 | self:copy(love.filesystem.getSaveDirectory()..'/lovefs_temp/temp.file', dest) 140 | return true 141 | end 142 | 143 | function lovefs(dir) 144 | local temp = {} 145 | setmetatable(temp, filesystem) 146 | temp.selectedFile = nil 147 | temp.filter = nil 148 | temp.showHidden = false 149 | temp.home = love.filesystem.getUserDirectory() 150 | temp.current = temp.home 151 | temp.sep = package.config:sub(1,1) 152 | dir = dir or temp.home 153 | if not temp:cd(dir) then 154 | if not temp:cd(temp.home) then 155 | if not temp:cd('c:'..sep) then 156 | temp:cd(sep) 157 | end 158 | end 159 | end 160 | temp:updDrives() 161 | return temp 162 | end 163 | -------------------------------------------------------------------------------- /lovefs/lovefs_linux.lua: -------------------------------------------------------------------------------- 1 | --[[------------------------------------ 2 | LoveFS v2.0 3 | Pure Lua FileSystem Access 4 | Under the MIT license. 5 | copyright(c) 2025 Caldas Lopes aka linux-man 6 | --]]------------------------------------ 7 | 8 | local ffi = require("ffi") 9 | 10 | ffi.cdef[[ 11 | struct dirent { 12 | unsigned long d_ino; /* inode number */ 13 | unsigned long d_off; /* not an offset */ 14 | unsigned short d_reclen; /* length of this record */ 15 | unsigned char d_type; /* type of file; not supported by all filesystem types */ 16 | char d_name[256]; /* filename */ 17 | }; 18 | ]] 19 | 20 | ffi.cdef[[ 21 | struct DIR *opendir(const char *name); 22 | struct dirent *readdir(struct DIR *dirstream); 23 | int closedir (struct DIR *dirstream); 24 | ]] 25 | 26 | local function join(tb1, tb2, tb3) 27 | local tb = {} 28 | for _,v in ipairs(tb1) do table.insert(tb, v) end 29 | for _,v in ipairs(tb2) do table.insert(tb, v) end 30 | for _,v in ipairs(tb3) do table.insert(tb, v) end 31 | return tb 32 | end 33 | 34 | local function removeValue(tb, value) 35 | for n = #tb, 1, -1 do 36 | if value == 'hidden' then 37 | if tb[n]:match('^%..') then table.remove(tb, n) end 38 | else 39 | if tb[n] == value then table.remove(tb, n) end 40 | end 41 | end 42 | end 43 | 44 | function filesystem:absPath(path) 45 | if path == '.' then path = self.current end 46 | if (path:sub(1,2) == '.'..self.sep) then path = self.current..path:sub(2) end 47 | if not (path:sub(1,1) == '/') then path = self.current..self.sep..path end 48 | path = path:gsub('\\', self.sep) 49 | path = path:gsub(self.sep..self.sep, self.sep) 50 | if #path > 1 and path:sub(-1) == self.sep then path = path:sub(1, -2) end 51 | return path 52 | end 53 | 54 | function filesystem:ls(dir) 55 | dir = dir or self.current 56 | dir = self:absPath(dir) 57 | local tDirs = {} 58 | local tFiles = {} 59 | local tOthers = {} 60 | local hDir = ffi.C.opendir(dir) 61 | ffi.gc(hDir, ffi.C.closedir) 62 | if hDir ~= nil then 63 | local dirent = ffi.C.readdir(hDir) 64 | while dirent ~= nil do 65 | local fn = ffi.string(dirent.d_name) 66 | if dirent.d_type == 4 then 67 | table.insert(tDirs, fn) 68 | elseif dirent.d_type == 8 then 69 | table.insert(tFiles, fn) 70 | else 71 | table.insert(tOthers, fn) 72 | end 73 | dirent = ffi.C.readdir(hDir) 74 | end 75 | end 76 | ffi.C.closedir(ffi.gc(hDir, nil)) 77 | if #tDirs == 0 then return false end 78 | removeValue(tDirs, '.') 79 | removeValue(tDirs, '..') 80 | if not (self.showHidden) then removeValue(tDirs, 'hidden') end 81 | table.sort(tDirs) 82 | if self.filter then 83 | for n = #tFiles, 1, -1 do 84 | local ext = tFiles[n]:match('[^.]+$') 85 | local valid = false 86 | for _, v in ipairs(self.filter) do 87 | valid = valid or (ext == v) 88 | end 89 | if not (valid) then table.remove(tFiles, n) end 90 | end 91 | end 92 | if not self.showHidden then removeValue(tFiles, 'hidden') end 93 | if not self.showHidden then removeValue(tOthers, 'hidden') end 94 | table.sort(tFiles) 95 | table.sort(tOthers) 96 | return dir, tDirs, tFiles, tOthers, join(tDirs, tFiles, tOthers) 97 | end 98 | 99 | function filesystem:updDrives() 100 | drives = {} 101 | dir, dirs = self:ls('/media') 102 | if dir then 103 | for n, d in ipairs(dirs) do dirs[n] = '/media/'..dirs[n] end 104 | drives = dirs 105 | end 106 | table.insert(drives, 1, '/') 107 | self.drives = drives 108 | end 109 | 110 | function filesystem:copy(source, dest) 111 | local inp = assert(io.open(source, "rb")) 112 | local out = assert(io.open(dest, "wb")) 113 | local data = inp:read("*all") 114 | out:write(data) 115 | assert(out:close()) 116 | end 117 | 118 | --https://github.com/3scale/luafilesystem-ffi/blob/master/lfs_ffi.lua 119 | ------------------------------ stat ------------------------------------ 120 | local MAXPATH = 4096 121 | local bit = require("bit") 122 | local band, bnot, rshift = bit.band, bit.bnot, bit.rshift 123 | local concat = table.concat 124 | 125 | local has_table_new, new_tab = pcall(require, "table.new") 126 | if not has_table_new or type(new_tab) ~= "function" then 127 | new_tab = function () return {} end 128 | end 129 | 130 | local stat_func 131 | local lstat_func 132 | 133 | ffi.cdef([[long syscall(int number, ...);]]) 134 | 135 | local stat_syscall_num 136 | local lstat_syscall_num 137 | 138 | ffi.cdef([[ 139 | typedef struct { 140 | unsigned long st_dev; 141 | unsigned long st_ino; 142 | unsigned long st_nlink; 143 | unsigned int st_mode; 144 | unsigned int st_uid; 145 | unsigned int st_gid; 146 | unsigned int __pad0; 147 | unsigned long st_rdev; 148 | long st_size; 149 | long st_blksize; 150 | long st_blocks; 151 | unsigned long st_atime; 152 | unsigned long st_atime_nsec; 153 | unsigned long st_mtime; 154 | unsigned long st_mtime_nsec; 155 | unsigned long st_ctime; 156 | unsigned long st_ctime_nsec; 157 | long __unused[3]; 158 | } stat; 159 | ]]) 160 | stat_syscall_num = 4 161 | lstat_syscall_num = 6 162 | 163 | if stat_syscall_num then 164 | stat_func = function(filepath, buf) 165 | return ffi.C.syscall(stat_syscall_num, filepath, buf) 166 | end 167 | lstat_func = function(filepath, buf) 168 | return ffi.C.syscall(lstat_syscall_num, filepath, buf) 169 | end 170 | else 171 | ffi.cdef('typedef struct {} stat;') 172 | stat_func = function() error("TODO support other Linux architectures") end 173 | lstat_func = stat_func 174 | end 175 | 176 | local STAT = { 177 | FMT = 0xF000, 178 | FSOCK = 0xC000, 179 | FLNK = 0xA000, 180 | FREG = 0x8000, 181 | FBLK = 0x6000, 182 | FDIR = 0x4000, 183 | FCHR = 0x2000, 184 | FIFO = 0x1000, 185 | } 186 | 187 | local ftype_name_map = { 188 | [STAT.FREG] = 'file', 189 | [STAT.FDIR] = 'directory', 190 | [STAT.FLNK] = 'link', 191 | [STAT.FSOCK] = 'socket', 192 | [STAT.FCHR] = 'char device', 193 | [STAT.FBLK] = "block device", 194 | [STAT.FIFO] = "named pipe", 195 | } 196 | 197 | ffi.cdef([[ 198 | char* strerror(int errnum); 199 | ]]) 200 | 201 | local function errno() 202 | return ffi.string(ffi.C.strerror(ffi.errno())) 203 | end 204 | 205 | local function mode_to_ftype(mode) 206 | local ftype = band(mode, STAT.FMT) 207 | return ftype_name_map[ftype] or 'other' 208 | end 209 | 210 | local function mode_to_perm(mode) 211 | local perm_bits = band(mode, tonumber(777, 8)) 212 | local perm = new_tab(9, 0) 213 | local i = 9 214 | while i > 0 do 215 | local perm_bit = band(perm_bits, 7) 216 | perm[i] = (band(perm_bit, 1) > 0 and 'x' or '-') 217 | perm[i-1] = (band(perm_bit, 2) > 0 and 'w' or '-') 218 | perm[i-2] = (band(perm_bit, 4) > 0 and 'r' or '-') 219 | i = i - 3 220 | perm_bits = rshift(perm_bits, 3) 221 | end 222 | return concat(perm) 223 | end 224 | 225 | local function time_or_timespec(time, timespec) 226 | local t = tonumber(time) 227 | if not t and timespec then 228 | t = tonumber(timespec.tv_sec) 229 | end 230 | return t 231 | end 232 | 233 | local attr_handlers = { 234 | access = function(st) return time_or_timespec(st.st_atime, st.st_atimespec) end, 235 | blksize = function(st) return tonumber(st.st_blksize) end, 236 | blocks = function(st) return tonumber(st.st_blocks) end, 237 | change = function(st) return time_or_timespec(st.st_ctime, st.st_ctimespec) end, 238 | dev = function(st) return tonumber(st.st_dev) end, 239 | gid = function(st) return tonumber(st.st_gid) end, 240 | ino = function(st) return tonumber(st.st_ino) end, 241 | mode = function(st) return mode_to_ftype(st.st_mode) end, 242 | modification = function(st) return time_or_timespec(st.st_mtime, st.st_mtimespec) end, 243 | nlink = function(st) return tonumber(st.st_nlink) end, 244 | permissions = function(st) return mode_to_perm(st.st_mode) end, 245 | rdev = function(st) return tonumber(st.st_rdev) end, 246 | size = function(st) return tonumber(st.st_size) end, 247 | uid = function(st) return tonumber(st.st_uid) end, 248 | } 249 | 250 | -- Add target field for symlinkattributes, which is the absolute path of linked target 251 | local get_link_target_path 252 | 253 | ffi.cdef('unsigned long readlink(const char *path, char *buf, size_t bufsize);') 254 | function get_link_target_path(link_path) 255 | local size = MAXPATH 256 | while true do 257 | local buf = ffi.new('char[?]', 512) 258 | local read = ffi.C.readlink(link_path, buf, size) 259 | if read == -1 then 260 | return nil, errno() 261 | end 262 | if read < size then 263 | return ffi.string(buf) 264 | end 265 | size = size * 2 266 | end 267 | end 268 | 269 | local mt = { 270 | __index = function(self, attr_name) 271 | local func = attr_handlers[attr_name] 272 | return func and func(self) 273 | end 274 | } 275 | local stat_type = ffi.metatype('stat', mt) 276 | 277 | local function attributes(filepath, attr, follow_symlink) 278 | local buf = ffi.new(stat_type) 279 | local func = follow_symlink and stat_func or lstat_func 280 | if func(filepath, buf) == -1 then 281 | return nil, errno() 282 | end 283 | 284 | local atype = type(attr) 285 | if atype == 'string' then 286 | local value 287 | if attr == 'target' and not follow_symlink then 288 | value = get_link_target_path(filepath) 289 | else 290 | value = buf[attr] 291 | end 292 | if value == nil then 293 | error("invalid attribute name '" .. attr .. "'") 294 | end 295 | return value 296 | else 297 | local tab = (atype == 'table') and attr or {} 298 | for k, _ in pairs(attr_handlers) do 299 | tab[k] = buf[k] 300 | end 301 | if not follow_symlink then 302 | tab.target = get_link_target_path(filepath) 303 | end 304 | return tab 305 | end 306 | end 307 | 308 | function filesystem:attr(filepath, attr, follow_symlink) 309 | if(follow_symlink == nil) then follow_symlink = false end 310 | return attributes(filepath, attr, follow_symlink) 311 | end 312 | ------------------------------ end stat -------------------------------- 313 | -------------------------------------------------------------------------------- /lovefs/lovefs_osx.lua: -------------------------------------------------------------------------------- 1 | --[[------------------------------------ 2 | LoveFS v2.0 3 | Pure Lua FileSystem Access 4 | Under the MIT license. 5 | copyright(c) 2025 Caldas Lopes aka linux-man 6 | --]]------------------------------------ 7 | 8 | local ffi = require("ffi") 9 | 10 | ffi.cdef[[ 11 | struct dirent { 12 | unsigned int d_fileno; /* inode number */ 13 | unsigned short d_reclen; /* length of this record */ 14 | char d_type; /* type of file; not supported by all filesystem types */ 15 | char d_namlen; /* length of filename */ 16 | char d_name[256] /* filename */ 17 | }; 18 | ]] 19 | 20 | ffi.cdef[[ 21 | struct DIR *opendir(const char *name); 22 | struct dirent *readdir(struct DIR *dirstream); 23 | int closedir (struct DIR *dirstream); 24 | ]] 25 | 26 | local function join(tb1, tb2, tb3) 27 | local tb = {} 28 | for _,v in ipairs(tb1) do table.insert(tb, v) end 29 | for _,v in ipairs(tb2) do table.insert(tb, v) end 30 | for _,v in ipairs(tb3) do table.insert(tb, v) end 31 | return tb 32 | end 33 | 34 | local function removeValue(tb, value) 35 | for n = #tb, 1, -1 do 36 | if value == 'hidden' then 37 | if tb[n]:match('^%..') then table.remove(tb, n) end 38 | else 39 | if tb[n] == value then table.remove(tb, n) end 40 | end 41 | end 42 | end 43 | 44 | function filesystem:absPath(path) 45 | if path == '.' then path = self.current end 46 | if (path:sub(1,2) == '.'..self.sep) then path = self.current..path:sub(2) end 47 | if not (path:sub(1,1) == '/') then path = self.current..self.sep..path end 48 | path = path:gsub('\\', self.sep) 49 | path = path:gsub(self.sep..self.sep, self.sep) 50 | if #path > 1 and path:sub(-1) == self.sep then path = path:sub(1, -2) end 51 | return path 52 | end 53 | 54 | function filesystem:ls(dir) 55 | dir = dir or self.current 56 | dir = self:absPath(dir) 57 | local tDirs = {} 58 | local tFiles = {} 59 | local tOthers = {} 60 | local hDir = ffi.C.opendir(dir) 61 | ffi.gc(hDir, ffi.C.closedir) 62 | if hDir ~= nil then 63 | local dirent = ffi.C.readdir(hDir) 64 | while dirent ~= nil do 65 | local fn = ffi.string(dirent.d_name) 66 | if dirent.d_type == 4 then 67 | table.insert(tDirs, fn) 68 | elseif dirent.d_type == 8 then 69 | table.insert(tFiles, fn) 70 | else 71 | table.insert(tOthers, fn) 72 | end 73 | dirent = ffi.C.readdir(hDir) 74 | end 75 | end 76 | ffi.C.closedir(ffi.gc(hDir, nil)) 77 | if #tDirs == 0 then return false end 78 | removeValue(tDirs, '.') 79 | removeValue(tDirs, '..') 80 | if not (self.showHidden) then removeValue(tDirs, 'hidden') end 81 | table.sort(tDirs) 82 | if self.filter then 83 | for n = #tFiles, 1, -1 do 84 | local ext = tFiles[n]:match('[^.]+$') 85 | local valid = false 86 | for _, v in ipairs(self.filter) do 87 | valid = valid or (ext == v) 88 | end 89 | if not (valid) then table.remove(tFiles, n) end 90 | end 91 | end 92 | if not self.showHidden then removeValue(tFiles, 'hidden') end 93 | if not self.showHidden then removeValue(tOthers, 'hidden') end 94 | table.sort(tFiles) 95 | table.sort(tOthers) 96 | return dir, tDirs, tFiles, tOthers, join(tDirs, tFiles, tOthers) 97 | end 98 | 99 | function filesystem:updDrives() 100 | drives = {} 101 | dir, dirs = self:ls('/Volumes') 102 | if dir then 103 | for n, d in ipairs(dirs) do dirs[n] = '/Volumes/'..dirs[n] end 104 | drives = dirs 105 | end 106 | table.insert(drives, 1, '/') 107 | self.drives = drives 108 | end 109 | 110 | function filesystem:copy(source, dest) 111 | local inp = assert(io.open(source, "rb")) 112 | local out = assert(io.open(dest, "wb")) 113 | local data = inp:read("*all") 114 | out:write(data) 115 | assert(out:close()) 116 | end 117 | 118 | --https://github.com/3scale/luafilesystem-ffi/blob/master/lfs_ffi.lua 119 | ------------------------------ stat ------------------------------------ 120 | MAXPATH = 1024 121 | local bit = require("bit") 122 | local band, bnot, rshift = bit.band, bit.bnot, bit.rshift 123 | local concat = table.concat 124 | 125 | local has_table_new, new_tab = pcall(require, "table.new") 126 | if not has_table_new or type(new_tab) ~= "function" then 127 | new_tab = function () return {} end 128 | end 129 | 130 | local stat_func 131 | local lstat_func 132 | 133 | ffi.cdef([[ 134 | struct timespec { 135 | time_t tv_sec; 136 | long tv_nsec; 137 | }; 138 | typedef struct { 139 | uint32_t st_dev; 140 | uint16_t st_mode; 141 | uint16_t st_nlink; 142 | uint64_t st_ino; 143 | uint32_t st_uid; 144 | uint32_t st_gid; 145 | uint32_t st_rdev; 146 | struct timespec st_atimespec; 147 | struct timespec st_mtimespec; 148 | struct timespec st_ctimespec; 149 | struct timespec st_birthtimespec; 150 | int64_t st_size; 151 | int64_t st_blocks; 152 | int32_t st_blksize; 153 | uint32_t st_flags; 154 | uint32_t st_gen; 155 | int32_t st_lspare; 156 | int64_t st_qspare[2]; 157 | } stat; 158 | int stat64(const char *path, stat *buf); 159 | int lstat64(const char *path, stat *buf); 160 | ]]) 161 | 162 | stat_func = ffi.C.stat64 163 | lstat_func = ffi.C.lstat64 164 | 165 | local STAT = { 166 | FMT = 0xF000, 167 | FSOCK = 0xC000, 168 | FLNK = 0xA000, 169 | FREG = 0x8000, 170 | FBLK = 0x6000, 171 | FDIR = 0x4000, 172 | FCHR = 0x2000, 173 | FIFO = 0x1000, 174 | } 175 | 176 | local ftype_name_map = { 177 | [STAT.FREG] = 'file', 178 | [STAT.FDIR] = 'directory', 179 | [STAT.FLNK] = 'link', 180 | [STAT.FSOCK] = 'socket', 181 | [STAT.FCHR] = 'char device', 182 | [STAT.FBLK] = "block device", 183 | [STAT.FIFO] = "named pipe", 184 | } 185 | 186 | ffi.cdef([[ 187 | char* strerror(int errnum); 188 | ]]) 189 | 190 | local function errno() 191 | return ffi.string(ffi.C.strerror(ffi.errno())) 192 | end 193 | 194 | local function mode_to_ftype(mode) 195 | local ftype = band(mode, STAT.FMT) 196 | return ftype_name_map[ftype] or 'other' 197 | end 198 | 199 | local function mode_to_perm(mode) 200 | local perm_bits = band(mode, tonumber(777, 8)) 201 | local perm = new_tab(9, 0) 202 | local i = 9 203 | while i > 0 do 204 | local perm_bit = band(perm_bits, 7) 205 | perm[i] = (band(perm_bit, 1) > 0 and 'x' or '-') 206 | perm[i-1] = (band(perm_bit, 2) > 0 and 'w' or '-') 207 | perm[i-2] = (band(perm_bit, 4) > 0 and 'r' or '-') 208 | i = i - 3 209 | perm_bits = rshift(perm_bits, 3) 210 | end 211 | return concat(perm) 212 | end 213 | 214 | local function time_or_timespec(time, timespec) 215 | local t = tonumber(time) 216 | if not t and timespec then 217 | t = tonumber(timespec.tv_sec) 218 | end 219 | return t 220 | end 221 | 222 | local attr_handlers = { 223 | access = function(st) return time_or_timespec(st.st_atime, st.st_atimespec) end, 224 | blksize = function(st) return tonumber(st.st_blksize) end, 225 | blocks = function(st) return tonumber(st.st_blocks) end, 226 | change = function(st) return time_or_timespec(st.st_ctime, st.st_ctimespec) end, 227 | dev = function(st) return tonumber(st.st_dev) end, 228 | gid = function(st) return tonumber(st.st_gid) end, 229 | ino = function(st) return tonumber(st.st_ino) end, 230 | mode = function(st) return mode_to_ftype(st.st_mode) end, 231 | modification = function(st) return time_or_timespec(st.st_mtime, st.st_mtimespec) end, 232 | nlink = function(st) return tonumber(st.st_nlink) end, 233 | permissions = function(st) return mode_to_perm(st.st_mode) end, 234 | rdev = function(st) return tonumber(st.st_rdev) end, 235 | size = function(st) return tonumber(st.st_size) end, 236 | uid = function(st) return tonumber(st.st_uid) end, 237 | } 238 | 239 | -- Add target field for symlinkattributes, which is the absolute path of linked target 240 | local get_link_target_path 241 | 242 | ffi.cdef('unsigned long readlink(const char *path, char *buf, size_t bufsize);') 243 | function get_link_target_path(link_path) 244 | local size = MAXPATH 245 | while true do 246 | local buf = ffi.new('char[?]', 512) 247 | local read = ffi.C.readlink(link_path, buf, size) 248 | if read == -1 then 249 | return nil, errno() 250 | end 251 | if read < size then 252 | return ffi.string(buf) 253 | end 254 | size = size * 2 255 | end 256 | end 257 | 258 | local mt = { 259 | __index = function(self, attr_name) 260 | local func = attr_handlers[attr_name] 261 | return func and func(self) 262 | end 263 | } 264 | local stat_type = ffi.metatype('stat', mt) 265 | 266 | local function attributes(filepath, attr, follow_symlink) 267 | local buf = ffi.new(stat_type) 268 | local func = follow_symlink and stat_func or lstat_func 269 | if func(filepath, buf) == -1 then 270 | return nil, errno() 271 | end 272 | 273 | local atype = type(attr) 274 | if atype == 'string' then 275 | local value 276 | if attr == 'target' and not follow_symlink then 277 | value = get_link_target_path(filepath) 278 | else 279 | value = buf[attr] 280 | end 281 | if value == nil then 282 | error("invalid attribute name '" .. attr .. "'") 283 | end 284 | return value 285 | else 286 | local tab = (atype == 'table') and attr or {} 287 | for k, _ in pairs(attr_handlers) do 288 | tab[k] = buf[k] 289 | end 290 | if not follow_symlink then 291 | tab.target = get_link_target_path(filepath) 292 | end 293 | return tab 294 | end 295 | end 296 | 297 | function filesystem:attr(filepath, attr, follow_symlink) 298 | if(follow_symlink == nil) then follow_symlink = false end 299 | return attributes(filepath, attr, follow_symlink) 300 | end 301 | ------------------------------ end stat -------------------------------- 302 | -------------------------------------------------------------------------------- /lovefs/lovefs_win.lua: -------------------------------------------------------------------------------- 1 | --[[------------------------------------ 2 | LoveFS v2.0 3 | Pure Lua FileSystem Access 4 | Under the MIT license. 5 | copyright(c) 2025 Caldas Lopes aka linux-man 6 | --]]------------------------------------ 7 | 8 | local ffi = require("ffi") 9 | 10 | ffi.cdef[[ 11 | #pragma pack(push) 12 | #pragma pack(1) 13 | struct WIN32_FIND_DATAW { 14 | uint32_t dwFileWttributes; 15 | uint64_t ftCreationTime; 16 | uint64_t ftLastAccessTime; 17 | uint64_t ftLastWriteTime; 18 | uint32_t dwReserved[4]; 19 | char cFileName[520]; 20 | char cAlternateFileName[28]; 21 | }; 22 | #pragma pack(pop) 23 | 24 | void* FindFirstFileW(const char* pattern, struct WIN32_FIND_DATAW* fd); 25 | bool FindNextFileW(void* ff, struct WIN32_FIND_DATAW* fd); 26 | bool FindClose(void* ff); 27 | bool CopyFileW(const char* src, const char* dst, bool bFailIfExists); 28 | int GetLogicalDrives(void); 29 | 30 | int MultiByteToWideChar(unsigned int CodePage, uint32_t dwFlags, const char* lpMultiByteStr, 31 | int cbMultiByte, const char* lpWideCharStr, int cchWideChar); 32 | int WideCharToMultiByte(unsigned int CodePage, uint32_t dwFlags, const char* lpWideCharStr, 33 | int cchWideChar, const char* lpMultiByteStr, int cchMultiByte, 34 | const char* default, int* used); 35 | ]] 36 | 37 | local WIN32_FIND_DATA = ffi.typeof('struct WIN32_FIND_DATAW') 38 | local INVALID_HANDLE = ffi.cast('void*', -1) 39 | 40 | local function u2w(str, code) 41 | local size = ffi.C.MultiByteToWideChar(code or 65001, 0, str, #str, nil, 0) 42 | local buf = ffi.new("char[?]", size * 2 + 2) 43 | ffi.C.MultiByteToWideChar(code or 65001, 0, str, #str, buf, size * 2) 44 | return buf 45 | end 46 | 47 | local function w2u(wstr, code) 48 | local size = ffi.C.WideCharToMultiByte(code or 65001, 0, wstr, -1, nil, 0, nil, nil) 49 | local buf = ffi.new("char[?]", size + 1) 50 | size = ffi.C.WideCharToMultiByte(code or 65001, 0, wstr, -1, buf, size, nil, nil) 51 | return ffi.string(buf) 52 | end 53 | 54 | local function join(tb1, tb2) 55 | local tb = {} 56 | for _,v in ipairs(tb1) do table.insert(tb, v) end 57 | for _,v in ipairs(tb2) do table.insert(tb, v) end 58 | return tb 59 | end 60 | 61 | local function removeValue(tb, value) 62 | for n = #tb, 1, -1 do 63 | if value == 'hidden' then 64 | if tb[n]:match('^%..') then table.remove(tb, n) end 65 | else 66 | if tb[n] == value then table.remove(tb, n) end 67 | end 68 | end 69 | end 70 | 71 | function filesystem:absPath(path) 72 | if path == '.' then path = self.current end 73 | if (path:sub(1,2) == '.'..self.sep) then path = self.current..path:sub(2) end 74 | if not (path:sub(2,2) == ':') then path = self.current..self.sep..path end 75 | path = path:gsub('/', self.sep) 76 | path = path:gsub(self.sep..self.sep, self.sep) 77 | if #path > 1 and path:sub(-1) == self.sep then path = path:sub(1, -2) end 78 | return path 79 | end 80 | 81 | function filesystem:ls(dir) 82 | dir = dir or self.current 83 | dir = self:absPath(dir) 84 | local tDirs = {} 85 | local tFiles = {} 86 | local tOthers = {} 87 | local fd = ffi.new(WIN32_FIND_DATA) 88 | local hFile = ffi.C.FindFirstFileW(u2w(dir..'\\*'), fd) 89 | ffi.gc(hFile, ffi.C.FindClose) 90 | if hFile ~= INVALID_HANDLE then 91 | repeat 92 | local fn = w2u(fd.cFileName) 93 | if fd.dwFileWttributes == 0x10 or fd.dwFileWttributes == 0x11 or (self.showHidden and fd.dwFileWttributes == 0x2012) then 94 | table.insert(tDirs, fn) 95 | elseif fd.dwFileWttributes == 0x20 or fd.dwFileWttributes == 0x2020 then 96 | table.insert(tFiles, fn) 97 | end 98 | until not ffi.C.FindNextFileW(hFile, fd) 99 | end 100 | ffi.C.FindClose(ffi.gc(hFile, nil)) 101 | if #tDirs == 0 then return false end 102 | removeValue(tDirs, '.') 103 | removeValue(tDirs, '..') 104 | table.sort(tDirs) 105 | if self.filter then 106 | for n = #tFiles, 1, -1 do 107 | local ext = tFiles[n]:match('[^.]+$') 108 | local valid = false 109 | for _, v in ipairs(self.filter) do 110 | valid = valid or (ext == v) 111 | end 112 | if not (valid) then table.remove(tFiles, n) end 113 | end 114 | end 115 | if not self.showHidden then removeValue(tFiles, 'hidden') end 116 | table.sort(tFiles) 117 | return dir, tDirs, tFiles, tOthers, join(tDirs, tFiles) 118 | end 119 | 120 | function filesystem:updDrives() 121 | drives = {} 122 | aCode = string.byte('A') 123 | drv = ffi.C.GetLogicalDrives() 124 | for n = 0, 15, 1 do 125 | if not(drv % 2 == 0) then table.insert(drives, string.char(aCode + n)..':\\') end 126 | drv = math.floor(drv / 2) 127 | end 128 | self.drives = drives 129 | end 130 | 131 | function filesystem:copy(source, dest) 132 | ffi.C.CopyFileW(u2w(source), u2w(dest), false) 133 | end 134 | 135 | --https://github.com/3scale/luafilesystem-ffi/blob/master/lfs_ffi.lua 136 | ------------------------------ stat ------------------------------------ 137 | local bit = require("bit") 138 | local band, bnot, rshift = bit.band, bit.bnot, bit.rshift 139 | local concat = table.concat 140 | 141 | local has_table_new, new_tab = pcall(require, "table.new") 142 | if not has_table_new or type(new_tab) ~= "function" then 143 | new_tab = function () return {} end 144 | end 145 | 146 | local stat_func 147 | local lstat_func 148 | 149 | ffi.cdef([[ 150 | typedef struct { 151 | unsigned int st_dev; 152 | unsigned short st_ino; 153 | unsigned short st_mode; 154 | short st_nlink; 155 | short st_uid; 156 | short st_gid; 157 | unsigned int st_rdev; 158 | int64_t st_size; 159 | long long st_atime; 160 | long long st_mtime; 161 | long long st_ctime; 162 | } stat; 163 | int _stat64(const char *path, stat *buffer); 164 | ]]) 165 | 166 | stat_func = ffi.C._stat64 167 | lstat_func = stat_func 168 | 169 | local STAT = { 170 | FMT = 0xF000, 171 | FSOCK = 0xC000, 172 | FLNK = 0xA000, 173 | FREG = 0x8000, 174 | FBLK = 0x6000, 175 | FDIR = 0x4000, 176 | FCHR = 0x2000, 177 | FIFO = 0x1000, 178 | } 179 | 180 | local ftype_name_map = { 181 | [STAT.FREG] = 'file', 182 | [STAT.FDIR] = 'directory', 183 | [STAT.FLNK] = 'link', 184 | [STAT.FSOCK] = 'socket', 185 | [STAT.FCHR] = 'char device', 186 | [STAT.FBLK] = "block device", 187 | [STAT.FIFO] = "named pipe", 188 | } 189 | 190 | ffi.cdef([[ 191 | char* strerror(int errnum); 192 | ]]) 193 | 194 | local function errno() 195 | return ffi.string(ffi.C.strerror(ffi.errno())) 196 | end 197 | 198 | local function mode_to_ftype(mode) 199 | local ftype = band(mode, STAT.FMT) 200 | return ftype_name_map[ftype] or 'other' 201 | end 202 | 203 | local function mode_to_perm(mode) 204 | local perm_bits = band(mode, tonumber(777, 8)) 205 | local perm = new_tab(9, 0) 206 | local i = 9 207 | while i > 0 do 208 | local perm_bit = band(perm_bits, 7) 209 | perm[i] = (band(perm_bit, 1) > 0 and 'x' or '-') 210 | perm[i-1] = (band(perm_bit, 2) > 0 and 'w' or '-') 211 | perm[i-2] = (band(perm_bit, 4) > 0 and 'r' or '-') 212 | i = i - 3 213 | perm_bits = rshift(perm_bits, 3) 214 | end 215 | return concat(perm) 216 | end 217 | 218 | local function time_or_timespec(time, timespec) 219 | local t = tonumber(time) 220 | if not t and timespec then 221 | t = tonumber(timespec.tv_sec) 222 | end 223 | return t 224 | end 225 | 226 | local attr_handlers = { 227 | access = function(st) return time_or_timespec(st.st_atime, st.st_atimespec) end, 228 | blksize = function(st) return tonumber(st.st_blksize) end, 229 | blocks = function(st) return tonumber(st.st_blocks) end, 230 | change = function(st) return time_or_timespec(st.st_ctime, st.st_ctimespec) end, 231 | dev = function(st) return tonumber(st.st_dev) end, 232 | gid = function(st) return tonumber(st.st_gid) end, 233 | ino = function(st) return tonumber(st.st_ino) end, 234 | mode = function(st) return mode_to_ftype(st.st_mode) end, 235 | modification = function(st) return time_or_timespec(st.st_mtime, st.st_mtimespec) end, 236 | nlink = function(st) return tonumber(st.st_nlink) end, 237 | permissions = function(st) return mode_to_perm(st.st_mode) end, 238 | rdev = function(st) return tonumber(st.st_rdev) end, 239 | size = function(st) return tonumber(st.st_size) end, 240 | uid = function(st) return tonumber(st.st_uid) end, 241 | } 242 | 243 | local mt = { 244 | __index = function(self, attr_name) 245 | local func = attr_handlers[attr_name] 246 | return func and func(self) 247 | end 248 | } 249 | local stat_type = ffi.metatype('stat', mt) 250 | 251 | local function attributes(filepath, attr) 252 | local buf = ffi.new(stat_type) 253 | local func = stat_func or lstat_func 254 | if func(filepath, buf) == -1 then 255 | return nil, errno() 256 | end 257 | 258 | local atype = type(attr) 259 | if atype == 'string' then 260 | local value 261 | value = buf[attr] 262 | if value == nil then 263 | error("invalid attribute name '" .. attr .. "'") 264 | end 265 | return value 266 | else 267 | local tab = (atype == 'table') and attr or {} 268 | for k, _ in pairs(attr_handlers) do 269 | tab[k] = buf[k] 270 | end 271 | return tab 272 | end 273 | end 274 | 275 | function filesystem:attr(filepath, attr) 276 | return attributes(filepath, attr) 277 | end 278 | ------------------------------ end stat -------------------------------- 279 | -------------------------------------------------------------------------------- /lovefs/luigiDialog.lua: -------------------------------------------------------------------------------- 1 | --[[------------------------------------ 2 | LoveFS Luigi Dialogs v1.0 3 | Pure Lua FileSystem Access - Loveframes interface 4 | Under the MIT license. 5 | copyright(c) 2016 Caldas Lopes aka linux-man 6 | --]]------------------------------------ 7 | 8 | local path = string.sub(..., 1, string.len(...) - string.len('luigiDialog'))..'images/' 9 | local widgetHeight = 26 10 | local maxScroll = 0 11 | local nFiles = 0 12 | 13 | local function closeDialog(self) 14 | self.dialog:hide() 15 | self.dialog = nil 16 | end 17 | 18 | local function updDialog(self) 19 | for n = 1, nFiles do 20 | table.remove(self.dialog.files) 21 | end 22 | self.dialog.filename.value = '' 23 | nFiles = #self.dirs + #self.files + 1 24 | local el = {type = 'button', style = 'up', text = '..'} 25 | self.dialog:createWidget(el) 26 | el:onPress(function (event) 27 | self:up() 28 | updDialog(self) 29 | end) 30 | self.dialog.files:addChild(el) 31 | for _, v in ipairs(self.dirs) do 32 | local el = {type = 'button', style = 'dir', text = v} 33 | self.dialog:createWidget(el) 34 | el:onPress(function (event) 35 | self:cd(event.target.text) 36 | updDialog(self) 37 | end) 38 | self.dialog.files:addChild(el) 39 | end 40 | for _, v in ipairs(self.files) do 41 | local el = {type = 'button', style = 'file', text = v} 42 | self.dialog:createWidget(el) 43 | el:onPress(function (event) 44 | self.dialog.filename.value = event.target.text 45 | self.dialog.filename:reshape() 46 | end) 47 | self.dialog.files:addChild(el) 48 | end 49 | 50 | maxScroll = nFiles * widgetHeight - self.dialog.files:getHeight() 51 | self.dialog.files.scrollY = 0 52 | self.dialog.files:reshape() 53 | self.dialog.slidey.value = 1 54 | self.dialog.current.text = self.current 55 | end 56 | 57 | local function init(self, Layout, label) 58 | self:cd() 59 | self.dialog = Layout( 60 | {type = 'submenu', width = 600, height = 400, 61 | {style = 'default', type = 'panel', align = 'middle center', text = label}, 62 | {style = 'default', flow = 'x', 63 | {style = 'comboButton', id = 'drives', text = 'Change Drive'}, 64 | {style = 'default', align = 'middle left', id = 'current'}, 65 | }, 66 | {padding = 0, flow = 'x', 67 | {id = 'files', padding = 0, flow = 'y', scroll = true}, 68 | {id = 'slidey', type = 'slider', width = 24, value = 1, flow = 'y'} 69 | }, 70 | {flow = 'x', style = 'default', 71 | {style = 'comboButton', id = 'filters', text = 'All | *.*'}, 72 | {style = 'default', align = 'middle left', type = 'text', id = 'filename', text = ''}, 73 | {style = 'dialogButton', id = 'cancelButton', text = 'Cancel'}, 74 | {style = 'dialogButton', id = 'okButton', text = 'OK'} 75 | } 76 | } 77 | ) 78 | 79 | self.dialog:setStyle( 80 | { 81 | default = { 82 | height = widgetHeight, 83 | margin = 0 84 | }, 85 | dialogButton = { 86 | type = 'button', 87 | width = 80, 88 | height = widgetHeight, 89 | margin = 0 90 | }, 91 | comboButton = { 92 | type = 'button', 93 | width = 140, 94 | height = widgetHeight, 95 | margin = 0 96 | }, 97 | up = { 98 | type = 'button', 99 | align = 'left middle', 100 | icon = path..'up.png', 101 | height = widgetHeight, 102 | margin = 0 103 | }, 104 | dir = { 105 | align = 'left middle', 106 | icon = path..'folder.png', 107 | height = widgetHeight, 108 | margin = 0 109 | }, 110 | file = { 111 | align = 'left middle', 112 | icon = path..'file.png', 113 | height = widgetHeight, 114 | margin = 0 115 | } 116 | } 117 | ) 118 | 119 | self.dialog.drives:onPress(function (event) 120 | local menu = {isContextMenu = true} 121 | for i, drive in ipairs(self.drives) do 122 | menu[#menu + 1] = {text = drive} 123 | end 124 | self.dialog:createWidget({type = 'menu', menu }) 125 | menu.menuLayout:onPress(function (event) 126 | self.dialog.drives.text = event.target.text 127 | self:cd(event.target.text) 128 | updDialog(self) 129 | end) 130 | menu.menuLayout:placeNear(self.dialog.drives:getX(), self.dialog.drives:getY() + self.dialog.drives:getHeight()) 131 | menu.menuLayout:show() 132 | end) 133 | 134 | self.dialog.slidey:onChange(function (event) 135 | self.dialog.files.scrollY = (1 - event.value) * maxScroll 136 | self.dialog.files:reshape() 137 | end) 138 | 139 | self.dialog.files:onWheelMove(function (event) 140 | self.dialog.slidey.value = 1 - self.dialog.files.scrollY / maxScroll 141 | end) 142 | 143 | self.dialog.cancelButton:onPress(function (event) 144 | closeDialog(self) 145 | end) 146 | 147 | self.dialog.okButton:onPress(function (event) 148 | if not(self.dialog.filename.value == '') then 149 | self.selectedFile = self:absPath(self.dialog.filename.value) 150 | closeDialog(self) 151 | end 152 | end) 153 | end 154 | 155 | function filesystem:loadDialog(Layout, label, filters) 156 | if self.dialog then closeDialog(self) end 157 | label = label or 'Load File' 158 | init(self, Layout, label) 159 | self.dialog.filename.type = 'panel' 160 | if filters and type(filters) == "table" then 161 | self.dialog.filters:onPress(function (event) 162 | local menu = {isContextMenu = true} 163 | for i, f in ipairs(filters) do 164 | menu[#menu + 1] = {text = f} 165 | end 166 | self.dialog:createWidget({type = 'menu', menu }) 167 | menu.menuLayout:onPress(function (event) 168 | self.dialog.filters.text = event.target.text 169 | self:setFilter(event.target.text) 170 | updDialog(self) 171 | end) 172 | menu.menuLayout:placeNear(self.dialog.filters:getX(), self.dialog.filters:getY() + self.dialog.filters:getHeight()) 173 | menu.menuLayout:show() 174 | end) 175 | self.dialog.filters.text = filters[1] 176 | self:setFilter(filters[1]) 177 | else 178 | self.dialog.filters.text = '*.*' 179 | self:setFilter(nil) 180 | end 181 | updDialog(self) 182 | self.dialog:show() 183 | end 184 | 185 | function filesystem:saveDialog(gspot, label) 186 | if self.dialog then closeDialog(self) end 187 | label = label or 'Save File' 188 | init(self, Layout, label) 189 | self.dialog.filters.width = 0 190 | self:setFilter(nil) 191 | updDialog(self) 192 | self.dialog:show() 193 | end 194 | --------------------------------------------------------------------------------