2017-05-22 22:16:30 +03:00

403 lines
13 KiB
Lua

require("advancedLua")
local unicode = require("unicode")
local buffer = require("doubleBuffering")
local event = require("event")
local fs = require("filesystem")
local context = require("context")
local ecs = require("ECSAPI")
--------------------------------------------------------------------------------------------------------------------------------
local xSize, ySize = buffer.width, buffer.height
local file = {}
local config = {
x = 1,
y = 1,
width = 98,
height = 25,
heightOfTopBar = 3,
fromString = 1,
xCurrentByte = 1,
yCurrentByte = 1,
pathToFile = "bin/resolution.lua",
sizeOfFile = 1,
transparency = 30,
colors = {
background = 0xdddddd,
topBar = 0xdddddd,
topBarText = 0x262626,
topBarButton = 0x444444,
hexText = 0x262626,
hexSelection = 0x880000,
hexSelectionText = 0xffffff,
numberBar = 0x262626,
numberBarText = 0xcccccc,
infoPanel = 0x880000,
infoPanelText = 0xffffff,
}
}
--------------------------------------------------------------------------------------------------------------------------------
local obj = {}
local function newObj(class, name, ...)
obj[class] = obj[class] or {}
obj[class][name] = {...}
end
local function convertIndexToCoords(index)
local ostatok = index % 16
local x = (ostatok == 0) and 16 or ostatok
local y = math.ceil(index / 16)
return x, y
end
local function convertCoordsToIndex(xByte, yByte)
return (yByte - 1) * 16 + xByte
end
local function readFile()
config.fromString = 1
config.CurrentByte = 1
config.CurrentByte = 1
file = {}
local fileStream = io.open(config.pathToFile, "rb")
while true do
local readedByte = fileStream:read(1)
if not readedByte then break end
table.insert(file, string.format("%02X", string.byte(readedByte)))
end
fileStream:close()
config.sizeOfFile = math.ceil(fs.size(config.pathToFile) / 1024)
end
local function drawInfoPanel()
local x = config.x
local y = config.y
local width = 30
local xPos = x + math.floor(config.width / 2 - width / 2) - 1
buffer.square(xPos, y, width, config.heightOfTopBar, config.colors.infoPanel, 0x000000, " ")
local text = fs.name(config.pathToFile)
xPos = x + math.floor(config.width / 2 - unicode.len(text) / 2) - 1
buffer.text(xPos, y, config.colors.infoPanelText, unicode.sub(text, 1, width - 2))
text = "Размер файла: " .. config.sizeOfFile .. " КБ"
xPos = x + math.floor(config.width / 2 - unicode.len(text) / 2) - 1
buffer.text(xPos, y + 1, 0xffaaaa, unicode.sub(text, 1, width - 2))
text = "Текущий байт: " .. convertCoordsToIndex(config.xCurrentByte, config.yCurrentByte)
xPos = x + math.floor(config.width / 2 - unicode.len(text) / 2) - 1
buffer.text(xPos, y + 2, 0xffaaaa, unicode.sub(text, 1, width - 2))
end
local function drawTopBar()
local x = config.x
local y = config.y
buffer.square(x, y, config.width, 3, 0xffffff, 0xffffff, " ", config.transparency)
newObj("Buttons", 1, buffer.button(x, y, 10, 3, 0xdddddd, 0x000000, "Файл"))
drawInfoPanel()
end
local function printDebug(line, text)
if debug then
ecs.square(1, line, buffer.width, 1, 0x262626)
ecs.colorText(2, line, 0xFFFFFF, text)
end
end
local function drawHexAndText()
local x, y = config.x, config.y + 3
local textOffset = 67
local hexOffset = 12
local xHex, yHex = x + hexOffset, y + 2
local xText, yText = xHex + textOffset, y + 2
obj["hex"] = {}
obj["text"] = {}
--Главный белый
buffer.square(config.x, config.y + 3, config.width, config.height - 3, config.colors.background, 0x000000, " ")
--Левый серый
buffer.square(x, y, 10, config.height - 3, config.colors.numberBar, 0xffffff, " ")
--Верхний серый
buffer.square(x, y, config.width, 1, config.colors.numberBar, 0xffffff, " ")
--Вертикальная полоска
buffer.square(xText - 3, y + 1, 1, config.height - 4, config.colors.background, 0xaaaaaa, "")
--Скроллбар
buffer.scrollBar(x + config.width - 1, y + 1, 1, config.height - 4, math.ceil(#file / 16), config.fromString, 0x262626, ecs.colors.lightBlue)
--Рисуем верхние номерки
local xCyka = xHex
for i = 1, 16 do
if i == config.xCurrentByte then
buffer.square(xCyka - 1, y, 4, 1, config.colors.hexSelection, 0xffffff, " ")
buffer.text(xCyka, y, config.colors.hexSelectionText, string.format("%02X", i - 1))
else
buffer.text(xCyka, y, config.colors.numberBarText, string.format("%02X", i - 1))
end
xCyka = xCyka + 4
end
--Рисуем хекс и текст
local xByte, yByte, text
local byteCounter = 1
local fromByte = config.fromString * 16 - 15
for byte = fromByte, fromByte + 10 * 16 - 1 do
if not file[byte] then break end
xByte, yByte = convertIndexToCoords(byte)
text = unicode.char(tonumber("0x" .. file[byte]))
if unicode.isWide(text) then text = "." end
if config.xCurrentByte == xByte and config.yCurrentByte == yByte then
buffer.square(xHex - 1, yHex, 4, 1, config.colors.hexSelection, 0xffffff, " ")
buffer.set(xText, yText, config.colors.hexSelection, 0xffffff, " ")
buffer.text(xHex, yHex, config.colors.hexSelectionText, file[byte])
buffer.text(xText, yText, config.colors.hexSelectionText, text)
else
buffer.text(xHex, yHex, config.colors.hexText, file[byte])
buffer.text(xText, yText, config.colors.hexText, text)
end
--Рисуем левые номерки
if yByte == config.yCurrentByte then
buffer.square(x, yHex, 10, 1, config.colors.hexSelection, 0xffffff, " ")
buffer.text(x + 1, yHex, config.colors.hexSelectionText, string.format("%07X", yByte - 1) .. "0")
else
buffer.text(x + 1, yHex, config.colors.numberBarText, string.format("%07X", yByte - 1) .. "0")
end
--Обжектыыы!! Ы!
newObj("hex", byteCounter, xHex, yHex, xByte, yByte)
newObj("text", byteCounter, xText, yText, xByte, yByte)
byteCounter = byteCounter + 1
--Коорды!
if xByte == 16 then
xHex = x + hexOffset
xText = xHex + textOffset
yHex = yHex + 2
yText = yText + 2
else
xHex = xHex + 4
xText = xText + 1
end
end
end
local function drawAll(force)
drawTopBar()
drawHexAndText()
--Тень
buffer.square(config.x + config.width, config.y + 1, 2, config.height, 0x000000, 0xffffff, " ", 50)
buffer.square(config.x + 2, config.y + config.height, config.width - 2, 1, 0x000000, 0xffffff, " ", 50)
buffer.draw(force)
end
local function getCenterOfScreen()
config.x = math.floor(xSize / 2 - config.width / 2)
config.y = math.floor(ySize / 2 - config.height / 2)
end
local function checkInput(text, pattern)
if string.find(text, pattern) then
return true
else
ecs.error("Что за говно ты сюда ввел? Переделывай на хуй!")
end
end
local function editByte(xByte, yByte)
local index = convertCoordsToIndex(xByte, yByte)
local data = ecs.universalWindow("auto", "auto", 36, 0x262626, true, {"EmptyLine"}, {"CenterText", 0xffffff, "Редактировать байт"}, {"EmptyLine"}, {"Input", 0xffffff, 0xff5555, "Введите значение HEX"}, {"EmptyLine"}, {"Button", {0x880000, 0xffffff, "Принять"}, {0xaaaaaa, 0xffffff, "Отмена"}})
if data[2] == "Принять" and checkInput(data[1], "^[1234567890abcdefABCDEF][1234567890abcdefABCDEF]$") then
file[index] = data[1]
end
end
local function editText(xByte, yByte)
local index = convertCoordsToIndex(xByte, yByte)
local data = ecs.universalWindow("auto", "auto", 36, 0x262626, true, {"EmptyLine"}, {"CenterText", 0xffffff, "Редактировать байт"}, {"EmptyLine"}, {"Input", 0xffffff, 0xff5555, "Введите значение CHAR"}, {"EmptyLine"}, {"Button", {0x880000, 0xffffff, "Принять"}, {0xaaaaaa, 0xffffff, "Отмена"}})
if data[2] == "Принять" and checkInput(data[1], "^.$") then
file[index] = string.format("%02X", string.byte(byteValue))
end
end
local function insertByte(xByte, yByte)
local index = convertCoordsToIndex(xByte, yByte)
local data = ecs.universalWindow("auto", "auto", 36, 0x262626, true, {"EmptyLine"}, {"CenterText", 0xffffff, "Вставить байт"}, {"EmptyLine"}, {"Input", 0xffffff, 0xff5555, "Введите значение HEX"}, {"EmptyLine"}, {"Button", {0x880000, 0xffffff, "Вставить"}, {0xaaaaaa, 0xffffff, "Отмена"}})
if data[2] == "Вставить" and checkInput(data[1], "^[1234567890abcdefABCDEF][1234567890abcdefABCDEF]$") then
table.insert(file, index, data[1])
end
end
local function invertByte(xByte, yByte)
local index = convertCoordsToIndex(xByte, yByte)
file[index] = bit32.band( bit32.bnot(tonumber("0x" .. file[index])), 0xff )
file[index] = string.format("%02X", string.byte(file[index]))
end
local function askForWhatToDoWithByte(x, y, xByte, yByte, asByte)
local action = context.menu(x, y, {"Редактировать байт"}, {"Инвертировать байт"}, {"Вставить байт"}, "-", {"Удалить байт"})
if action == "Редактировать байт" then
if asByte then
editByte(xByte, yByte)
else
editText(xByte, yByte)
end
elseif action == "Инвертировать байт" then
local index = convertCoordsToIndex(xByte, yByte)
invertByte(xByte, yByte)
elseif action == "Вставить байт" then
insertByte(xByte, yByte)
elseif action == "Удалить байт" then
local index = convertCoordsToIndex(xByte, yByte)
table.remove(file, index)
end
end
local function save(path)
fs.makeDirectory(fs.path(path) or "")
local fileStream = io.open(path, "w")
for i = 1, #file do
fileStream:write(unicode.char(tonumber(table.concat({"0x", file[i]}))))
end
fileStream:close()
end
--------------------------------------------------------------------------------------------------------------------------------
readFile()
--buffer.square(1, 1, xSize, ySize, ecs.colors.red, 0x000000, " ")
getCenterOfScreen()
local oldPixels = buffer.copy(config.x, config.y, config.width + 2, config.height + 1)
drawAll(true)
while true do
local e = {event.pull()}
if e[1] == "touch" then
for key in pairs(obj["hex"]) do
if e[3] >= obj["hex"][key][1] - 1 and e[3] <= obj["hex"][key][1] + 2 and e[4] == obj["hex"][key][2] then
if config.xCurrentByte == obj["hex"][key][3] and config.yCurrentByte == obj["hex"][key][4] then
if e[5] == 0 then
editByte(obj["hex"][key][3], obj["hex"][key][4])
else
askForWhatToDoWithByte(obj["hex"][key][1] - 1, obj["hex"][key][2] + 1, obj["hex"][key][3], obj["hex"][key][4], true)
end
else
config.xCurrentByte = obj["hex"][key][3]
config.yCurrentByte = obj["hex"][key][4]
end
drawHexAndText()
drawInfoPanel()
buffer.draw()
break
end
end
for key in pairs(obj["text"]) do
if e[3] == obj["text"][key][1] and e[4] == obj["text"][key][2] then
if config.xCurrentByte == obj["text"][key][3] and config.yCurrentByte == obj["text"][key][4] then
if e[5] == 0 then
editText(obj["text"][key][3], obj["text"][key][4])
else
askForWhatToDoWithByte(obj["text"][key][1], obj["text"][key][2] + 1, obj["text"][key][3], obj["text"][key][4], true)
end
else
config.xCurrentByte = obj["text"][key][3]
config.yCurrentByte = obj["text"][key][4]
end
drawHexAndText()
drawInfoPanel()
buffer.draw()
break
end
end
if ecs.clickedAtArea(e[3], e[4], obj["Buttons"][1][1], obj["Buttons"][1][2], obj["Buttons"][1][3], obj["Buttons"][1][4]) then
buffer.button(obj["Buttons"][1][1], obj["Buttons"][1][2], 10, 3, 0x333333, 0xdddddd, "Файл")
buffer.draw()
local action = context.menu(obj["Buttons"][1][1], obj["Buttons"][1][2] + 3, {"Открыть"}, {"Сохранить"}, {"Сохранить как"}, "-", {"Выход"})
buffer.button(obj["Buttons"][1][1], obj["Buttons"][1][2], 10, 3, 0xdddddd, 0x000000, "Файл")
buffer.draw()
if action == "Открыть" then
local data = ecs.universalWindow("auto", "auto", 36, 0x262626, true, {"EmptyLine"}, {"CenterText", 0xffffff, "Открыть файл"}, {"EmptyLine"}, {"Input", 0xffffff, 0x880000, "Путь к файлу"}, {"EmptyLine"}, {"Button", {0x880000, 0xffffff, "Открыть"}, {0xaaaaaa, 0xffffff, "Отмена"}})
if data[2] == "Открыть" then
if fs.exists(data[1]) then
config.pathToFile = data[1]
readFile()
drawHexAndText()
drawInfoPanel()
buffer.draw()
else
ecs.error("Файл \"" .. data[1] .. "\" не существует!")
end
end
elseif action == "Сохранить" then
save(config.pathToFile)
elseif action == "Сохранить как" then
local data = ecs.universalWindow("auto", "auto", 36, 0x262626, true, {"EmptyLine"}, {"CenterText", 0xffffff, "Сохранить как"}, {"EmptyLine"}, {"Input", 0xffffff, 0x880000, "Путь к файлу"}, {"EmptyLine"}, {"Button", {0x880000, 0xffffff, "Сохранить"}, {0xaaaaaa, 0xffffff, "Отмена"}})
if data[2] == "Сохранить" then
save(data[1])
end
elseif action == "Выход" then
buffer.paste(config.x, config.y, oldPixels)
buffer.draw()
return
end
end
elseif e[1] == "scroll" then
if e[5] == 1 then
if config.fromString > 1 then
config.fromString = config.fromString - 1
drawHexAndText()
buffer.draw()
end
else
if config.fromString <= math.ceil(#file / 16) - 1 then
config.fromString = config.fromString + 1
drawHexAndText()
buffer.draw()
end
end
end
end